我看到Haskell有一个名为"delay"的睡眠函数:Control.Concurrent.Thread.Delay
我的问题是:如果Haskell 纯粹是功能性的,怎么可能有这样的事情呢?睡觉不是附带效果还是我错过了什么?
Dan*_*zer 51
好吧,把我的评论转移到答案.请注意,IOmonad和这些想法有多个视图.您可以使用唯一性类型和诸如此类的方法获得类似的结果.
我碰巧发现这是最简单,最酷的解释.
Haskell是一种纯函数式语言.这应该意味着评估Haskell程序应该始终产生相同的结果.但是,情况似乎并非如此!看看像
-- Echo.hs
main :: IO ()
main = getLine >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
根据用户输入,这似乎有所不同.
IO事实上任何生活看起来都可以做出截然不同的事情,这取决于从月亮状态到薛定谔猫的人寿保险费用.
更过,好像任何可以做任何事情必须是不纯的有用的语言.除非你有兴趣观察你的CPU旋转,否则产生副作用就是所有程序都存在!
事实上事实并非如此!适当的心理模型是想象IO的东西
data IO a = PutStrLn String a
| GetLine (String -> a)
...
Run Code Online (Sandbox Code Playgroud)
因此,IO可能只是一个数据结构,代表程序执行的一种"计划".然后邪恶的不纯Haskell运行时实际执行此计划,产生您看到的结果.
这不仅仅是一个小的语义狡辩,我们可以做类似的事情
runBackwards :: [IO ()] -> IO ()
runBackwards = foldr (>>) (return ()) . reverse
Run Code Online (Sandbox Code Playgroud)
换句话说,我们可以将我们的"计划"作为正常的第一类价值来操纵.
我们可以对它们进行评估,强制它们,在它们上面放一些砖块,甚至在背后说出关于它们的意思,它们永远不会产生副作用!你不能看到,普通的Haskell代码只能构建IO运行时要评估的动作,它无法做任何明显的事情.
在某种程度上,您几乎可以将Haskell程序视为元编程的最终形式,在运行时动态生成程序并由一些解释器对它们进行评估.
所以当你说
foo = delay 20
Run Code Online (Sandbox Code Playgroud)
你并没有说"延迟这个程序为20个whatevers",你说"在这个代码构建的程序中,当它运行时暂停执行20个whatevers".
问"谁关心"是公平的:如果这个代码在某个点上运行谁关心谁运行它?以这种方式纯粹功能有什么用?它实际上可以有一些有趣的效果(嘿).
例如,想想像http://www.tryhaskell.org这样的东西,显然它需要运行Haskell代码,但它也不能盲目地执行任何IO它得到的东西!它可以做的是提供不同的实现IO,同时暴露相同的API.
这个新IO建立了一个很好的树,就像数据结构一样,可以很容易地被Web后端清理和检查,以确保它永远不会运行邪恶的东西.我们甚至可以将我们的假IO结构编译为GHC提供的正常结构,并在服务器上有效地执行它!因为从一开始就没有任何邪恶,我们只需要信任我们编写的代码.
没有更多无尽的applet风格的安全漏洞.通过替换,IO我们知道我们可以执行此代码并且永远不会尝试做一些邪恶的事情.
事实上,这种构建数据结构的概念不仅仅是有用的IO.这是构建旨在提供有限DSL的任何项目的好方法.来自的任何东西
所有这些都可以通过构建普通数据结构并将它们"编译"为适当的语言来解决.通常的诀窍是使用免费的monad.如果你是中级Haskeller,那就去学习吧!
"纯功能"是一个有趣的术语.
一开始就需要处理现实世界的一切都不是纯粹的功能.但不知何故,Haskell需要处理现实世界.否则语言没有意义.
所以解决方案是IO monad.我不会在这里详细介绍(我相信你可以找到IO monad的另一个解释).IO monad大致是该类型的函数RealWorld -> RealWorld.
这意味着我们不是在我们的计划之外做一些事情,而是假装现实世界将成为我们计划的一部分,每当我们想要改变现实世界中的某些东西时,我们就会创造另一个我们更喜欢的现实世界.
诀窍delay在于我们采用当前世界并创建另一个世界,其中时间提前了给定的秒数.