Joh*_*aze 34 io monads functional-programming side-effects
monad被描述为处理IO的haskell解决方案.我想知道是否有其他方法可以用纯函数式语言处理IO.
Nor*_*sey 35
在纯函数式语言中,I/O的monad有哪些替代方案?
我知道文献中有两种选择:
一种是所谓的线性类型系统.这个想法是线性类型的值必须恰好使用一次:你不能忽略它,你不能使用它两次.考虑到这个想法,你给世界的状态一个抽象类型(例如World
),并使它成为线性的.如果我用星号标记线性类型,那么这里是一些I/O操作的类型:
getChar :: World* -> (Char, World*)
putChar :: Char -> World* -> World*
Run Code Online (Sandbox Code Playgroud)
等等.编译器安排确保你永远不会复制世界,然后它可以安排编译更新世界的代码,这是安全的,因为只有一个副本.
在Clean语言中输入的唯一性基于线性.
该系统具有几个优点; 特别是,它不会强制monad所做事件的总排序.它也倾向于避免IO
你在Haskell中看到的" sin bin",其中所有有效的计算都被抛入IO
monad中,无论你是否想要总命令,它们都会完全有序.
我所知道的另一个系统早于monad和Clean,并且基于这样的想法:交互式程序是从(可能是无限的)请求序列到(可能是无限的)响应序列的函数.这个被称为"对话"的系统纯粹是编程的地狱.没有人会错过它,并没有特别推荐它.在Wadler和Peyton Jones 介绍monadic I/O(Imperative Functional Programming)的论文中,它的错误很好地列举了.本文还提到了一个基于延续的I/O系统,该系统由耶鲁Haskell小组引入但是很短暂.
如果"纯粹"是指"引用透明",也就是说,应用函数可以与其评估结果自由交换(因此,每次调用具有相同参数的函数都具有相同的结果),任何有状态IO的概念几乎被排除在外.
我知道有两个粗略的策略:
让一个函数执行IO,但要确保它永远不会被完全相同的参数调用两次; 这方面通过让功能简单地"引用透明"来解决问题.
将整个程序视为单个纯函数,将"接收到的所有输入"作为参数并返回"产生的所有输出",两者都由某种形式的惰性流表示以允许交互.
有多种方法可以实现这两种方法,以及一定程度的重叠 - 例如,在第二种情况下,在I/O流上运行的函数不太可能在流的相同部分被调用两次.以何种方式查看它更有意义取决于语言为您提供何种支持.
在Haskell中,IO
是一种monad类型,它通过代码自动地对顺序状态进行线程化(类似于功能上纯粹的State
monad),这样,从概念上讲,每次调用其他不纯函数都会获得隐含的"外部世界状态"的不同值. ".
我所知道的另一种流行的方法是使用线性类型到类似的结尾; 通过具有无法复制或复制的值,确保不纯函数永远不会获得相同的参数两次,因此"外部世界状态"的旧值不能保留并重复使用.