在哈斯克尔睡觉 [英] Sleep in Haskell

查看:133
本文介绍了在哈斯克尔睡觉的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到Haskell有一个名为delay的睡眠函数: Control.Concurrent.Thread.Delay



我的问题是:如果Haskell完全是功能,那么怎么可能拥有这样的事情?是不是睡眠的副作用,或者我错过了什么?

解决方案

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



我刚碰巧找到这个最简单最酷的解释。



伪造杂质



Haskell是一种纯粹的函数式语言。这应该意味着评估一个Haskell程序应该总是产生相同的结果。但是,这似乎并不是这样!看看类似于

   -  Echo.hs 
main :: IO()
main = getLine > = putStrLn

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



实际上,任何生活在 IO 中的东西看起来都可以做很多不同的事情,取决于从月亮状态到生活的所有事情薛定谔的猫的保险费用。

更重要的是,任何能够做任何有用的操作的语言似乎都是不纯的。除非你有兴趣观看你的CPU,否则产生的副作用就是所有程序存在的!



邪恶解释器



其实这其实并非如此!适当的心智模式是将 IO 想象为类似于

 数据IO a = PutStrLn字符串a 
| GetLine(String - > a)
...

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



这不仅仅是一个小的语义诡计,我们可以做一些像

p>

  runBackwards :: [IO()]  - > IO()
runBackwards = foldr(>>)(return())。反向

换句话说,我们可以将我们的计划作为正常的头等值操作。



我们可以对它们进行评估,强迫它们,在它们身上放下大量的砖块,甚至在它们的背后说出关于它们的意思,并且它们永远不会产生副作用!他们不能看到,正常的Haskell代码只能建立 IO 动作,以便在运行时进行评估,而不能做任何明显的事情。



通过某种方式,您几乎可以将Haskell程序视为元编程的终极形式,在运行时即时生成程序,并由某个解释器进行评估。

所以当你说

  foo =延迟20 

你不是说延迟这个程序为20个凡是,你说在程序中这个代码建立了,暂停执行20个发起者当它运行。



谁在乎



这是公平的问谁在乎:如果这段代码得到谁在乎谁管理它的时候运行?它有什么好处,以这种方式纯粹的功能?它实际上可以有一些有趣的效果(heh)。

例如,想一些像 http ://www.tryhaskell.org ,显然它需要运行Haskell代码,但它也不能盲目地执行它获得的任何 IO !它可以做的是提供一个不同的实现 IO ,同时暴露相同的API。

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



没有更多无尽的小应用程序式安全漏洞。通过替换 IO ,我们知道我们可以执行此代码,并且永远不会尝试做一些坏事。



邪恶解释器无处不在



实际上,这种构建数据结构的概念对于 IO 。这是构建旨在提供有限DSL的任何项目的好方法。来自的任何内容


  • 查询语言

  • 游戏脚本

  • 代码生成

  • 编写客户端haskell

    $ b $ p

    所有这些都可以通过建立正常的数据结构并将其编译为适当的语言。通常的技巧是使用免费的monad 。如果你是一个中级Haskeller,去了解em!


    I saw Haskell has a sleep function called "delay": Control.Concurrent.Thread.Delay

    My question is: if Haskell is purely functional, how is it possible to have such thing like this? Isn't sleep a collateral effect or am I missing something?

    解决方案

    Alright, moving my comment to an answer. Do note that there are multiple views of the IO monad and these ideas. You can achieve similar results with uniqueness types and whatnot.

    I just happen to find this the simplest and coolest explanation.

    Faking Impurity

    Haskell is a purely functional language. This should mean that evaluating a Haskell program should always produce the same results. However, that doesn't seem like the case! Look at something like

    -- Echo.hs
    main :: IO ()
    main = getLine >>= putStrLn
    

    This seems to do something different depending on user input.

    Really anything that lives in IO looks like it can do wildly different things depending on everything from the state of the moon to the life insurance costs of Schrodinger's cat.

    More over, it seems like any language that can do anything useful must be impure. Unless your interested in watching your CPU spin, producing side effects is all that programs exist for after all!

    Evil Interpreters

    In fact this isn't actually the case! The appropriate mental model is to imagine IO as something like

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

    So IO could just be a data structure representing a sort of "plan" for the program to execute. Then the evil impure Haskell runtime actually executes this plan, producing the results you see.

    This isn't just a minor semantic quibble though, we can do something like

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

    In other words we can manipulate our "plans" as normal, first class values.

    We can evaluate them, force them, drop a ton of bricks on them, even say mean things about them behind their backs and they'll never produce a side effect! They can't you see, normal Haskell code can only build up IO actions to be evaluated by the run time, it's incapable of doing anything noticeable.

    In a way you can almost view a Haskell program as the ultimate form of metaprogramming, producing programs on the fly during runtime and having them evaluated by some interpreter.

    So when you say

     foo = delay 20
    

    You're not saying "Delay this program for 20 whatevers", you're saying "In the program that this code builds, pause its execution for 20 whatevers when it runs".

    Who Cares

    It's fair to ask "Who Cares": if this code gets run at some point who cares who runs it? What good does it do to be purely functional in this way? It can actually have some interesting effects (heh).

    For example, think of something like http://www.tryhaskell.org, clearly it needs to run Haskell code, but it also can't just blindly execute whatever IO it gets! What it can do is provide a different implementation of IO, while exposing an identical API.

    This new IO builds up a nice tree like datastructure which can be easily sanitized and checked by the web backend to ensure that it never runs something evil. We can even compile our fake-IO structure to the normal one that GHC provides and execute it efficiently on the server! Since there's never anything evil in their to begin with we only have to trust code we wrote.

    No more endless applet-style security holes. By replacing IO we know beyond a shadow of a doubt that we can execute this code and it will never attempt to do something evil.

    Evil Interpreters Everywhere

    In fact, this notion of building up data structures is useful for more than just IO. It's a great way to structure any project that aims to provide a limited DSL. Anything from

    • A query language
    • Game scripting
    • Code generation
    • Writing "client side haskell"

    All of these can be solved by building up normal datastructures and "compiling" them to the appropriate language. The usual trick for this is to use a free monad. If you're an intermediate Haskeller, go learn about em!

    这篇关于在哈斯克尔睡觉的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆