monad在纯函数式编程中使用IO的替代方法是什么?

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",其中所有有效的计算都被抛入IOmonad中,无论你是否想要总命令,它们都会完全有序.

  • 我所知道的另一个系统早于monad和Clean,并且基于这样的想法:交互式程序是从(可能是无限的)请求序列到(可能是无限的)响应序列的函数.这个被称为"对话"的系统纯粹是编程的地狱.没有人会错过它,并没有特别推荐它.在Wadler和Peyton Jones 介绍monadic I/O(Imperative Functional Programming)的论文中,它的错误很好地列举.本文还提到了一个基于延续的I/O系统,该系统由耶鲁Haskell小组引入但是很短暂.

  • 延续形成一个单子,但单子绝对不是*延续.CPS更强大,因为你可以复制东西(包括延续!).Monads比仅仅进行类型检查更严格地限制事物. (2认同)

Wei*_* Hu 8

除线性类型外,还有效果系统.


Dou*_*rie 5

Clean 中使用唯一性类型


C. *_*ann 5

如果"纯粹"是指"引用透明",也就是说,应用函数可以与其评估结果自由交换(因此,每次调用具有相同参数的函数都具有相同的结果),任何有状态IO的概念几乎被排除在外.

我知道有两个粗略的策略:

  • 让一个函数执行IO,但要确保它永远不会被完全相同的参数调用两次; 这方面通过让功能简单地"引用透明"来解决问题.

  • 将整个程序视为单个纯函数,将"接收到的所有输入"作为参数并返回"产生的所有输出",两者都由某种形式的惰性流表示以允许交互.

有多种方法可以实现这两种方法,以及一定程度的重叠 - 例如,在第二种情况下,在I/O流上运行的函数不太可能在流的相同部分被调用两次.以何种方式查看它更有意义取决于语言为您提供何种支持.

在Haskell中,IO是一种monad类型,它通过代码自动地对顺序状态进行线程化(类似于功能上纯粹的Statemonad),这样,从概念上讲,每次调用其他不纯函数都会获得隐含的"外部世界状态"的不同值. ".

我所知道的另一种流行的方法是使用线性类型到类似的结尾; 通过具有无法复制或复制的值,确保不纯函数永远不会获得相同的参数两次,因此"外部世界状态"的旧值不能保留并重复使用.


Dan*_*kov 5

如果您对功能IO感兴趣,Peyton Jones和Wadler的命令式功能编程必读.他们讨论的其他方法是:

  • 对话是懒惰的响应和请求流

type Dialogue = [Response] -> [Request]

main :: Dialogue

  • 延续 - 每个IO操作都以延续为参数

  • 线性类型 - 类型系统以不能复制或破坏外部状态的方式限制您,这意味着您无法以相同的状态调用函数两次.


Dob*_*eer 5

函数式反应式编程是处理这个问题的另一种方法。

  • 我从未听说过“函数响应式编程”这个术语。能改成“函数式响应式编程”吗?否则很好的答案。 (3认同)