2017-02-27 51 views
0

有没有干净的方式,以避免以下样板:安全记录字段查询

给定一个记录数据类型定义....

data Value = A{ name::String } | B{ name::String } | C{} 

编写安全返回name

getName :: Value -> Maybe String 
getName A{ name=x } = Just x 
getName B{ name=x } = Just x 
getName C{} = Nothing 
功能

我知道你可以用模板Haskell做到这一点,我正在寻找一个比这更清洁的soln,也许是GHC扩展或其他我忽略的东西。

+0

无论如何,这不会无法编译在香草GHC,因为你不能有重载记录字段? – jkeuhlen

+0

@jkeuhlen不会。它会创建一个部分函数'name :: Value - > String',它在'name C'中出现'*** Exception:记录选择器名称中不匹配'的错误。您正在考虑具有_different_数据类型中的共享字段的记录。 – Alec

+0

您在数据类型定义中引入了对这种样板文件的需求。相反,你可以写'数据Value = AorB Bool String | C; getName(AorB _ x)= x; getName _ = Nothing' – user2407038

回答

4

lensTemplate Haskell helpers当他们遇到部分记录字段时做正确的事情。

{-# LANGUAGE TemplateHaskell #-} 


import Control.Applicative 
import Control.Lens 


data T = A { _name :: String } 
     | B { _name :: String } 
     | C 

makeLenses ''T 

这会产生一个名为Traversal'name选择AB构造内String,所以没有任何的C情况。

ghci> :i name 
name :: Traversal' T String -- Defined at test.hs:11:1 

所以我们可以使用the ^? operator(这是preview翻转代名词)从Control.Lens.Fold拔出Maybe名称。

getName :: T -> Maybe String 
getName = (^? name) 

您也可以Prism'为了你们的数据类型的构造函数,并选择那些匹配使用<|>的第一个。当你的构造函数的字段有不同的名字时,这个版本很有用,但是当你添加构造函数时你必须记得更新你的提取函数。

makePrisms ''T 

getName' :: T -> Maybe String 
getName' t = t^?_A <|> t^?_B 

lens非常有用!

0

为什么不使用GADT?我不知道你是否有兴趣只使用记录。但是,我认为GADT为您的问题提供了一个干净的解决方案,因为您可以通过改进类型来限制构造函数的有效性。

{-# LANGUAGE GADTs #-} 

module Teste where 

data Value a where 
    A :: String -> Value String 
    B :: String -> Value String 
    C :: Value() 

name :: Value String -> String 
name (A s) = s 
name (B s) = s 

注意两个AB产生Value String值而产生CValue()。当你定义函数

name :: Value String -> String 

它具体说你只能传递一个包含字符串的值。因此,您只能对AB值进行模式匹配。这对于避免在代码中需要Maybe很有用。

+1

也许你的意思是'A :: {name :: String} - > Value String'和' B :: {name :: String} - > Value String'?这样,'name :: Value String - > String'就会自动生成。 – Alec

+0

@Alec:我在我的GHC版本8.0.1上试过这样的语法,它不起作用。也许我错过了什么? –

+0

您是否启用了'-XGADTs'?如果是这样,它应该工作(并且已经有很多GHC版本)。见[this](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#generalised-algebraic-data-types-gadts)。 – Alec