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

oro*_*ome 11 haskell pattern-matching

我有

data Foo = X (String, Int) | A String | B String | C String | D String -- ...
Run Code Online (Sandbox Code Playgroud)

并已定义

f (X (s, _)) =s 
f (A s) = s
f (B s) = s
f (C s) = s
f (D s) = s
-- ...
Run Code Online (Sandbox Code Playgroud)

但我宁愿能写出类似的东西

f (X (s, _)) =s 
f (_ s) = s
Run Code Online (Sandbox Code Playgroud)

但似乎没有办法做到这一点(我得到了与之相关的"解析错误" _).

有没有办法在Haskell中匹配数据构造函数通配符?

Dan*_*ner 17

不.但你可以这样写:

data Foo
    = X { name :: String, age :: Int } 
    | A { name :: String }
    | B { name :: String }
    | C { name :: String }
    | D { name :: String }
Run Code Online (Sandbox Code Playgroud)

然后有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
Run Code Online (Sandbox Code Playgroud)

  • @raxacoricofallapatorius,如果字符串在每种情况下代表相同的东西,标签方法是有道理的.如果字符串不相关,您可能需要三个构造函数.事实上,你想对字符串做同样的事情,无论如何暗示,但并不暗示,标记的方法是有道理的. (2认同)

Pet*_*lák 5

除了@DanielWagner 的回答之外,另一种方法是使用Scrap 您的样板(又名“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
Run Code Online (Sandbox Code Playgroud)

并且fooString将返回第一个String你的构造函数的参数。函数cast过滤掉Strings 并gmapQ获取所有直接子项的过滤值。

但是,这不会返回Stringfrom X,因为X没有直接String子项,它只有一个类型为 的子项(String, Int)。为了String在术语层次结构中的任何位置获得第一个,您可以使用everywhere

fooString' :: Foo -> Maybe String
fooString' = everything mplus cast
Run Code Online (Sandbox Code Playgroud)

请注意,这种方法有点脆弱:它仅包含String它找到的所有s,这可能并不总是您想要的,特别是如果您稍后扩展您的数据类型(或它引用的某些数据类型)。