睡在哈斯克尔

时间:2014-08-29 20:59:26

标签: haskell

我看到Haskell有一个名为"延迟的睡眠功能":Control.Concurrent.Thread.Delay

我的问题是:如果Haskell 纯粹功能,怎么可能有这样的事情呢?是不是会产生附带影响,或者我错过了什么?

3 个答案:

答案 0 :(得分:49)

好的,将我的评论转移到答案。请注意,IO monad和这些想法有多个视图。您可以使用唯一性类型和诸如此类的方法获得类似的结果。

我碰巧发现这是最简单,最酷的解释。

伪造杂质

Haskell是一种纯函数式语言。这应该意味着评估Haskell程序应该始终产生相同的结果。但是,情况似乎并非如此!看看像

这样的东西
-- Echo.hs
main :: IO ()
main = getLine >>= putStrLn

根据用户输入,这似乎有所不同。

真正生活在IO的任何东西看起来都可以做出截然不同的事情,这取决于从月亮状态到薛定谔猫的人寿保险费用。

更重要的是,似乎任何语言可以做任何有用的事情必须是不纯的。除非你有兴趣观察你的CPU旋转,否则产生副作用就是所有程序都存在!

邪恶的口译员

实际上事实并非如此!适当的心智模型是将IO想象为

data IO a = PutStrLn String a
          | GetLine (String -> a)
          ...

因此IO可能只是一个数据结构,代表程序执行的一种“计划”。然后邪恶的不纯Haskell运行时实际上执行这个计划,产生你看到的结果。

这不仅仅是一个小的语义狡辩,我们可以做类似

的事情
runBackwards :: [IO ()] -> IO ()
runBackwards  = foldr (>>) (return ()) . reverse

换句话说,我们可以将我们的“计划”视为正常的第一类价值。

我们可以对它们进行评估,强制它们,在它们上面放一些砖块,甚至在背后说出关于它们的意思,它们永远不会产生副作用!他们你不能看到,普通的Haskell代码只能构建IO动作以便在运行时进行评估,它无法做任何明显的事情。

在某种程度上,您几乎可以将Haskell程序视为元编程的最终形式,在运行时动态生成程序并由某些解释程序对其进行评估。

所以当你说

 foo = delay 20

你不是说“延迟这个程序为20个whatevers”,你说“在这个代码构建的程序中,当它运行时暂停执行20个whatevers”。

谁关心

问“谁关心”是公平的:如果这个代码在某个时候运行谁关心谁运行它?以这种方式纯粹功能有什么用?它实际上可以有一些有趣的效果(呵呵)。

例如,考虑像http://www.tryhaskell.org这样的东西,显然它需要运行Haskell代码,但它也不能盲目地执行它获得的任何IO!它可以做的是提供IO的不同实现,同时公开相同的API。

这个新的IO构建了一个像数据结构一样漂亮的树,可以通过Web后端轻松清理和检查,以确保它永远不会运行邪恶的。我们甚至可以将假的IO结构编译为GHC提供的正常结构,并在服务器上有效地执行它!因为从一开始就没有任何邪恶,我们只需要信任我们编写的代码。

没有更多无尽的applet风格的安全漏洞。通过替换IO,我们知道我们可以执行此代码并且它永远不会尝试做一些邪恶的事情。

邪恶的口译员

事实上,这种构建数据结构的概念不仅仅对IO有用。这是构建旨在提供有限DSL的任何项目的好方法。

中的任何内容
  • 查询语言
  • 游戏脚本
  • 代码生成
  • 写“客户端haskell”

所有这些都可以通过构建普通的数据结构并将它们“编译”为适当的语言来解决。通常的诀窍是使用free monad。如果你是中级Haskeller,那就去了解em!

答案 1 :(得分:6)

“纯功能”是一个有趣的术语。

首先需要处理现实世界的一切都不是纯粹的功能。但不知何故,Haskell需要处理现实世界。否则语言没有意义。

所以解决方案是IO monad。我不会在这里详细介绍(我相信你可以找到IO monad的另一个解释)。 IO monad大致是RealWorld -> RealWorld类型的函数。

这意味着我们不是在我们的计划之外做某些事情,而是假装现实世界将成为我们计划的一部分,每当我们想要改变现实世界中的某些东西时,我们就会创造另一个我们更喜欢的现实世界。 / p>

delay的诀窍在于我们采用当前世界并创建另一个世界,其中时间提前了给定的秒数。

答案 2 :(得分:-5)

纯函数式语言不应具有类似"延迟"," writeFile"等功能,因为它们会产生副作用。但是Haskell具有这些功能,它通过一个名为IO的容器来处理它们,这个容器也是一个monad。 IO隐藏了这些功能所产生的所有副作用。