kis*_*aya 3 syntax haskell types
(我对Haskell相当新)我创建了这样的数据类型 -
data MatchingCondition = MatchingHead String | MatchingBody String | MatchingTail String
现在我想编写一个extractCondition :: MatchingCondition -> String从该数据类型中提取字符串的函数.
一种方法是明确地写
extractCondition (MatchingHead x) = x
extractCondition (MatchingBody x) = x
extractCondition (MatchingTail x) = x
Run Code Online (Sandbox Code Playgroud)
现在,案例很少,所以我可以很容易地写下这个函数,但如果有更多的案例,或者将来我要为我的数据类型添加更多条件,那将会变得非常痛苦.那么有没有简单的方法来做到这一点.
此外,当我的朋友看到这段代码时,他评论说:这似乎首先打败了sum-type引入的类型安全性.
有人可以解释这究竟是什么意思吗?
为构造函数编写下划线是一件好事:
extractCondition (_ x) = x
Run Code Online (Sandbox Code Playgroud)
不幸的是你无法在Haskell中编写这样的代码.
但是您可以随时重构代码以将标记移动到单独的字段中:
data MatchingType = Head | Body | Tail
data MatchingCondition = Match MatchingType String
extractCondition (Match _ x) = x
Run Code Online (Sandbox Code Playgroud)
存在一些技术,您只需编写类似的东西extract @String myMatching,它将自动String从每个构造函数返回.而且您根本不需要编写任何代码!(请参阅报废样板).虽然它可能不是你想要的.
另一个答案中基于记录的解决方案也是一种有效的解决方案.虽然你应该小心在总和类型中记录.这可能很危险!
再类型安全失败:更好地问你的朋友,因为他说了这个.但是如果不看整个代码就很难说出他的意思.
我只会说明这一点:
此外,当我的朋友看到这段代码时,他评论说:这似乎首先打败了sum-type引入的类型安全性.
有人可以解释这究竟是什么意思吗?
你的朋友可能担心将来你会添加一些没有String内部的构造函数.
考虑:
data T = A String | B String
getString :: T -> String
getString (A s) = s
getString (B s) = s
Run Code Online (Sandbox Code Playgroud)
这没有什么不妥,只要T是固定的.
相反,如果稍后T改变,我们可能会最终结果
data T = A String | B String | C NotAString
getString :: T -> String
getString (A s) = s
getString (B s) = s
getString (C n) = error "not a string, let's make the program crash!"
Run Code Online (Sandbox Code Playgroud)
如果T以这种方式扩展,则getString成为部分功能,应该避免.在一个函数周围有这样的函数很想写代码如
foo :: T -> ...
foo t = use (getString t)
Run Code Online (Sandbox Code Playgroud)
并且"忘记"非字符串情况,可能导致程序崩溃.如果foo必须在所有构造函数上进行模式匹配,我们也会记住这种情况.
当T扩展时,类型getString :: T -> String成为用户的谎言.它告诉他们String将永远产生一个,但事实并非如此.典型的解决方案,包括删除getString,让foo做所有的模式匹配,或者,如果"最"的情况下,有一个字符串,保留getString,但将其更改为getString :: T -> Maybe String让foo现在将被迫处理"无弦"的情况.
我还要提到要避免的常见设计错误,这是"布尔盲"的情况.一些程序员很想保持getString :: T -> String局部,并添加辅助函数
hasString :: T -> Bool
Run Code Online (Sandbox Code Playgroud)
有意使用
foo t = if hasString t
then use (getString t)
else handleNoString
Run Code Online (Sandbox Code Playgroud)
这里的问题是使用必须记住每个getString调用必须受到保护hasString.编译器无法帮助程序员.这给程序员带来了更多的负担,程序员必须积极避免危险情况.如果我们Maybe改为使用,那么这个问题就不存在了.
foo t = case getString t of
Just s -> use s -- now use (getString t) would be a type error, and rightly so!
Nothing -> handleNoString
Run Code Online (Sandbox Code Playgroud)
这种设计存在于某些Java库中,这可能有助于它的普及.(我被告知许多Java程序员现在认为它是一个糟糕的设计.)