我可以在Haskell中匹配数据构造函数通配符吗?

时间:2015-08-22 16:05:03

标签: haskell pattern-matching

我有

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中匹配数据构造函数通配符?

2 个答案:

答案 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 ,它可能并不总是你想要的,特别是如果你以后扩展你的数据类型(或者它的某些数据类型)参考文献)。