有没有一种干净的方法来避免以下样板:
给定一个记录数据类型定义...。
data Value = A{ name::String } | B{ name::String } | C{}
Run Code Online (Sandbox Code Playgroud)
编写安全返回的函数 name
getName :: Value -> Maybe String
getName A{ name=x } = Just x
getName B{ name=x } = Just x
getName C{} = Nothing
Run Code Online (Sandbox Code Playgroud)
我知道您可以使用Template Haskell做到这一点,我正在寻找一种比这更清洁的解决方案,也许是GHC扩展或其他我忽略的东西。
lens的模板Haskell助手在遇到部分记录字段时会做正确的事情。
{-# LANGUAGE TemplateHaskell #-}
import Control.Applicative
import Control.Lens
data T = A { _name :: String }
| B { _name :: String }
| C
makeLenses ''T
Run Code Online (Sandbox Code Playgroud)
这会产生一个Traversal'名为name该选择String内部A和B建设者和无助的C情况下。
ghci> :i name
name :: Traversal' T String -- Defined at test.hs:11:1
Run Code Online (Sandbox Code Playgroud)
因此,我们可以使用的^?运算符(这是一个翻转的代名词preview),从Control.Lens.Fold拔出Maybe的名称。
getName :: T -> Maybe String
getName = (^? name)
Run Code Online (Sandbox Code Playgroud)
您还可以使Prism's作为数据类型的构造函数,并使用来选择与之匹配的第一个<|>。当构造函数的字段具有不同的名称时,此版本很有用,但是您一定要记住在添加构造函数时更新提取器函数。
makePrisms ''T
getName' :: T -> Maybe String
getName' t = t^?_A <|> t^?_B
Run Code Online (Sandbox Code Playgroud)
lens 非常有用!