由于副作用破坏了引用透明度,它们是否违背了函数式语言的要点?
答案 0 :(得分:22)
纯函数式编程语言使用两种技术来模拟副作用:
1)表示外部状态的世界类型,其中该类型的每个值都由类型系统保证仅使用一次。
在使用此方法的语言中,函数print
和read
可能分别具有(string, world) -> world
和world -> (string, world)
类型。
他们可能会像这样使用:
let main w =
let w1 = print ("What's your name?", w) in
let (str, w2) = read w1 in
let w3 = print ("Your name is " ^ name, w2) in
w3
但不是这样的:
let main w =
let w1 = print ("What's your name?", w) in
let (str, w2) = read w in
let w3 = print ("Your name is " ^ name, w2) in
w3
(因为w使用了两次)
所有带副作用的内置函数都会获取并返回一个世界值。由于所有带副作用的函数都是内置函数或调用其他具有副作用的函数,这意味着所有带副作用的函数都需要获取并返回一个世界。
这样就不可能使用相同的参数调用带有副作用的函数两次,并且不会违反参照透明度。
2)IO monad,其中所有带副作用的操作都必须在该monad中执行。
使用此方法,所有带副作用的操作都将具有类型io something
。例如,print
是一个类型为string -> io unit
的函数,而read
的类型为io string
。
访问执行操作值的唯一方法是使用“monadic bind”操作(例如,在haskell中称为>> =),IO操作作为一个参数,以及描述如何处理的函数结果作为另一个操作数。
上面的例子看起来像是monadic IO:
let main =
(print "What's your name?") >>=
(lambda () -> read >>=
(lambda name -> print ("Your name is " ^ name)))
答案 1 :(得分:12)
有多种选项可用于处理函数式语言的I / O.
a research dissertation详尽地分析了这些。
功能I / O是一个正在进行的研究领域,还有其他语言以有趣和精神错乱的方式解决了这个问题。 Hoare logic用于某些研究语言。其他人(如Mercury)使用uniqueness typing。还有一些人(如Clean)使用effect systems。其中我对水星的接触非常非常有限,所以我无法对细节做出真正的评论。有一个paper详细介绍了Clean的I / O系统,但是,如果你对这个方向感兴趣的话。
答案 2 :(得分:1)
据我所知,如果你想在功能语言中有副作用,你必须明确地对它们进行编码。