21

我是一个完整的新手,目前正在尝试通过“ Learn You a Haskell for Great Good ”来学习 Haskell。我已经到了解释如何使用命令行参数的部分,有些东西让我很烦。

根据我的理解(以及haskell.org 的定义),操作旨在封装副作用。命令行参数是程序给定实例的不可变输入,那么拥有getProgName :: IO String而不是有什么意义getProgName :: String呢?换一种说法:阻止纯函数调用有什么意义getProgName

更新

到目前为止,我对这个问题有一些很好的答案。我接受Don Stewart 的文章是最简单和简洁的,但Conal 的(及其相关的博客文章)绝对值得一读。

4

3 回答 3

25

首先,getArgs可以在运行时更改。见withArgs

其次,getArgs属于getProgName一类有趣的不纯计算——它们在程序运行期间被认为是常量,但是,它们在编译时不是可用的值,并且它们从一个程序运行到另一个程序运行时会发生变化。它们没有明确的外延。

参见例如较早的讨论,其中讨论了 getArgs 和浮点计算。甚至可以认为 minBound/maxBound 属于此类。

于 2013-01-12T17:51:32.387 回答
24

要回答这些问题,您需要一个基础:表达式e具有类型是什么意思t?您可以为 之类的原语给出任意答案getProgName,但您不必这样做。相反,请查看表达式和类型的含义。当由 表示的值(即作为数学值的含义)属于由 表示的集合时,就说表达式e具有类型。teet

现在考虑t == String。我们想要String拥有什么意义?同样,这里有很多选择空间。然而,用最简单的数学定义选择有用的候选人有很多优点。在 HaskellString == [Char]中,我们真正讨论的是[]和的含义。Char 我所知道的最引人注目的简单候选词是[]表示列表(序列)和Char表示字符,因此表示字符String序列,即“字符串”。

选择String意味着字符串,现在我们可以询问是否有可能getProgName :: String. 如果是这样,那么 的含义getProgName必须是一个字符序列。但是,没有单一的字符序列可以捕捉到getProgName. (编辑:据推测,getProgName当它出现在不同名称的程序中时,您希望产生不同的字符串。)因此,我们必须选择不同的类型,例如(但不一定)IO String,或者我们必须选择更复杂的含义String. 后一条路线起初可能看起来很吸引人,直到您考虑到深层含义。纯函数式(更准确地说是“外延”)编程支持实用、严谨的推理,这要归功于使用简单的含义,如序列,而不是复杂的含义,如来自某种环境的函数,包括操作系统、机器执行上下文。

有关密切相关的评论和讨论,请参阅博客文章Haskell 中的纯度概念

编辑:我认为 Peter Landin(Haskell 的祖父)用他对“外延式编程”(或“真正的函数式编程”)的定义表达得最好,他建议将其作为“声明式”和“函数式”编程等模糊术语的实质性替代. 有关参考、引用和简短评论,请参阅帖子Haskell是纯函数式语言吗?.

于 2013-01-12T19:03:24.653 回答
3

我的理解是纯函数是纯函数,因为您可以在“代码时”对它们进行推理,而编译器可以在编译时进行推理。IO 操作取决于运行时。getArgs,它只在程序运行时为程序提供参数,因此是一个 IO 操作。

正如Learn you a Haskell所说:

您可以将 I/O 操作想象成一个带有小脚的盒子,它会进入现实世界并在那里做一些事情(比如在墙上涂鸦)并可能带回一些数据。

我们不知道小脚的盒子在代码时或编译时会带来什么。

于 2013-01-12T17:58:50.450 回答