我有
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中匹配数据构造函数通配符?
答案 0 :(得分:17)
不。但你可以这样写:
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
答案 1 :(得分:4)
除了@ DanielWagner的答案之外,另一种方法是使用Scrap your boilerplate(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
s和gmapQ
获取所有直接子项的过滤值。
但是,这不会从String
返回X
,因为X
没有立即String
子项,它只有一个类型{{1}的子项}。要在术语层次结构中的任何位置获取第一个(String, Int)
,您可以使用everywhere
:
String
请注意,这种方法有点脆弱:它只包含它找到的所有fooString' :: Foo -> Maybe String
fooString' = everything mplus cast
,它可能并不总是你想要的,特别是如果你以后扩展你的数据类型(或者它的某些数据类型)参考文献)。