给出具有记录语法的示例数据类型:
data VmInfo = VmInfo {infoVid :: String
,infoIndex :: Int
,infoPid :: Int
,infoExe :: String
} deriving (Show)
和(vmInfo :: String - > VmInfo)函数,它生成并返回上面给定vm名称为字符串的数据结构。
我可以看到两种方法来提取VmInfo数据类型的各个部分。
(VmInfo vid _ _ _) <- vmInfo vm
这只是模式匹配。而且......
vid <- infoVid <$> vmInfo vm
使用记录语法编译器生成的函数。
问题很简单:哪种方法更受欢迎?
打字量明智,他们是相同的,所以我正在寻找速度和正确/最佳实践。
我认为模式匹配会更快,但记录语法的重点是什么?
感谢。
答案 0 :(得分:8)
这些在语义上不等同。
让我们看看第一个例子:
(VmInfo vid _ _ _) <- vmInfo vm
这在绑定操作中执行模式匹配。有两个结果。第一个是评估vmInfo vm
动作结果的构造函数。这意味着,如果vmInfo
以return undefined
之类的行结尾,则评估undefined
时引发的异常将在此模式匹配时发生,而不是稍后使用vid
。第二个是如果模式匹配被反驳(模式匹配与值不匹配),将使用模式匹配错误文本调用monad的fail
实例。在这种情况下,这是不可能的,但通常可以在模式匹配绑定中的构造函数时使用。
现在,转到下一个例子:
vid <- infoVid <$> vmInfo vm
根据<$>
的定义,这将在动作返回的值(而不是效果)中完全是懒惰的。如果vmInfo
以return undefined
结尾,则在您使用undefined
的值执行操作之前,您不会从评估vid
获得异常。此外,如果infoVoid
能够抛出任何异常,那么在使用vid
之前最终不会发生这种情况,最好的情况。
有趣的是,这些差异仅出现在monadic绑定的范围内。如果vmInfo
是纯粹的,并且您在vid
或let
表达式中绑定了名称where
,则它们会生成相同的代码。
在这种情况下,您想要使用哪一个完全取决于您。两者都是惯用的Haskell。人们通常会选择在他们工作的环境中看起来更好的一面。
人们使用访问器函数的主要原因是简洁性,当记录有很多字段,模式匹配很大,并且因为它们是实际函数 - 它们可以传递给它们的类型适合的任何高阶函数。您不能将模式匹配作为不同的构造传递。