Могу ли я сопоставить шаблон конструктора данных в Haskell?
У меня
data Foo = X (String, Int) | A String | B String | C String | D String -- ...
и определили
f (X (s, _)) =s
f (A s) = s
f (B s) = s
f (C s) = s
f (D s) = s
-- ...
но предпочтет написать что-то вроде
f (X (s, _)) =s
f (_ s) = s
Но, похоже, нет способа сделать это (я получаю "синтаксическую ошибку", связанную с _
).
Есть ли способ сопоставления шаблона конструктора данных в Haskell?
Ответы
Ответ 1
Неа. Но вы можете написать это:
data Foo
= X { name :: String, age :: Int }
| A { name :: String }
| B { name :: String }
| C { name :: String }
| D { name :: String }
а затем name :: Foo -> String
. Вы могли бы также рассмотреть это:
data Tag = A | B | C | D
data Foo = X String Int | Tagged Tag String
f (X s _) = s
f (Tagged _ s) = s
Ответ 2
В дополнение к ответу @DanielWagner альтернативой является использование Отменить ваш шаблон (AKA "SYB" ). Он позволяет вам найти первый подтерм данного типа. Таким образом, вы можете определить
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Monad
import Data.Data
import Data.Generics.Schemes
import Data.Typeable
data Foo = X (String, Int) | A String | B String | C String | D String
deriving (Show, Eq, Ord, Data, Typeable)
fooString :: Foo -> Maybe String
fooString = msum . gmapQ cast
и fooString
вернут первый аргумент String
ваших конструкторов. Функция cast
отфильтровывает String
и gmapQ
получает отфильтрованные значения для всех непосредственных субтерм.
Однако это не вернет String
из X
, потому что X
не имеет непосредственного подтерминала String
, он имеет только один подтерм типа (String, Int)
. Чтобы получить первый String
в любом месте иерархии терминов, вы можете использовать everywhere
:
fooString' :: Foo -> Maybe String
fooString' = everything mplus cast
Обратите внимание, что этот подход слегка хрупкий: он включает в себя просто все String
, которые он находит, что может быть не всегда то, что вы хотите, в частности, если позднее вы расширите свой тип данных (или некоторый тип данных, который он ссылается).