6

给定一个具有记录语法的示例数据类型:

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

使用记录语法编译器生成的函数。

问题很简单:哪种方法是首选方法?

明智的打字量它们是相同的,所以我正在寻找速度和正确性/最佳实践。

我假设模式匹配会更快,但是记录语法有什么意义呢?

谢谢。

4

1 回答 1

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, best case.

有趣的是,这些差异只存在于单子绑定的范围内。如果vmInfo是纯的并且您将名称绑定到vidorlet表达式where中,它们将生成相同的代码。

在这种情况下,您要使用哪一个完全取决于您。两者都是惯用的 Haskell。人们通常会选择在他们工作的环境中看起来更好的那个。

人们使用访问器函数的主要原因是简洁,因为记录具有如此多的字段,模式匹配很大,并且因为它们是实际函数 - 它们可以传递给其类型适合的任何高阶函数。您不能将模式匹配作为不同的构造传递。

于 2012-04-24T04:22:51.170 回答