我正在研究在纯编程语言中产生计算效果的可能方法。
Monads 通常作为一种在纯语言中包装副作用的方式呈现。不过,我看不出他们有什么帮助。我看到的问题是可以复制或丢弃单子。
在纯语言中,操作的结果应该只取决于它的参数。但是用一种假设的语言
putStrLn :: String -> IO ()
编码
let a = putStrLn "1"
let b = putStrLn "2"
in ()
将获取类型Unit
并且无法捕获副作用的存在。
我以后也可以
let a1 = do
_ <- a
_ <- putStrLn "2.1"
let a2 = do
_ <- a
_ <- putStrLn "2.2"
in ()
大概将(不是最新的)状态a
分为两条路径a1
和a2
. 还是所有效果都延迟到IO ()
从主函数返回一个选定的术语?然后我想知道如何编译保持可变状态的可复制单子(当单子确实分歧时,在什么时候以及如何复制状态?)
相比之下,独特的类型似乎能够自然地捕捉到唯一一个上下文的存在
putStrLn :: 1 IO () -> String -> 1 IO ()
main :: 1 IO () -> 1 IO ()
main io =
let a = putStrLn io "1"
let b = putStrLn a "2"
// compile error, a has type 0 IO ()
// let a1 = putStrLn a "2.1"
in b
这似乎捕捉到状态被不可逆转地修改并且无法再次访问。因此,函数调用的所有结果确实只取决于它们的参数。