共享意味着如果要使用多次,则将存储临时数据。也就是说,一个函数只对它的参数求值一次。一个例子是:

let x = sin x in x * x

还有哪些其他功能有助于共享,它们将如何与执行IO的实际程序的需求互动?

最佳答案

函数式编程中最清晰的共享示例来自Clean,它基于图形重写。在那里,计算涉及到DAG,因此我们可以将表达式(sin x) * (sin x)视为

    (*)
  /     \
sin x   sin x

图重写系统具有明确的共享概念,因此我们可以将该计算表示为
   (*)
   / \
   \ /
  sin x

将乘法节点指向同一节点,从而共享sin x的计算。术语重写系统没有如此明确的共享概念,但是优化仍然很重要。在GHC中,有时可以表示与局部变量的共享,例如改写
f x = (sin x) * (sin x)

进入
f x = sinx * sinx
  where sinx = sin x

但是由于两者在语义上是等效的,因此编译器可以自由地以相同的方式实现这两种方式,无论共享与否。根据我的理解,GHC通常会保留使用局部变量引入的共享,有时还会引入共享(将共享添加到第一个变量),但是在术语重写系统中没有共享的正式表达,要么行为取决于实现(请参阅tel的评论和回答)。

共享涉及IO,因为无法共享副作用值。如果我们认为一种不纯正的语言,
(string-append (read-line)
               (read-line))


(let ((s (read-line)))
  (string-append s s))

第一个执行两次IO操作,向用户请求两行并附加它们;第二行执行IO操作。第二个“共享” IO操作,执行一次并将其附加到自身。通常,共享一个纯计算会减少执行时间而不会更改程序的结果,而共享一个副作用值(一个可能随时间变化或与用户交互的值)会更改结果。为了使编译器自动共享计算,它需要知道它们是纯净的,因此减少求值次数无关紧要。 Clean通过唯一性类型来做到这一点; IO操作具有类型属性UNQ,该属性告诉编译器不应共享该属性。 Haskell对IO monad的处理方式有所不同。

关于haskell - 在功能编程语言的实现中共享指的是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16430376/

10-16 06:56