2015-10-28 85 views
12

我一次又一次读到有效的,但我仍然无法给出它的含义的明确定义。我认为正确的上下文是effectful 计算,但我也看到了我以前认为effectful手段有副作用术语effectful values“有效”究竟意味着什么

。但是在Haskell中没有副作用(除了某种程度上IO)。仍然有各地有效的计算。

然后我读到monads用于创建有效的计算。我可以在State Monad的背景下对此有所了解。但是我没有看到在monod中有任何副作用。一般来说,在我看来,包装一个类似功能的东西的Monad比包装一个值的Monad更容易被看作是产生副作用。

说到Applicative仿函数我更迷路了。我总是看到应用函数作为一种具有多个参数的函数map。这里我看不到任何副作用。或者效果如何效果

+0

也许有用:https://slpopejoy.github.io/posts/Effectful01.html他定义*效果*为:1.实际的副作用(IO)2.似乎是副作用的东西(状态,作家等等)3.持续在函数调用(读取器,状态等)上的上下文4.非局部控制流(可能,任一)。 –

+3

大多数单子是用纯粹的计算来定义的,但从程序员的角度来看,通常认为'将状态sa'看作是一个必要的子程序,可以读/写具有副作用的状态's',最后产生一个'a'。即使它是纯粹的,有时假装它不是很方便。关于主题,我认为效果和效果意味着同样的事情,即使它们有时会广泛应用于任何monad/applicative中包含的值,即使这些值没有对副作用建模。 – chi

回答

3

在我看来,“副作用”是指正常功能无法做到的任何事情。换句话说,除了仅仅返回一个值以外,还有其他的东西。

考虑下面的代码块:

let 
    y = foo x 
    z = bar y 
in foobar z 

这就需要foo,然后调用bar,然后调用foobar,三台普通功能。很简单,对吗?现在考虑这个:

do 
    y <- foo x 
    z <- bar y 
    foobar z 

这也需要三个功能,但它也无形中要求每对线之间(>>=)为好。这意味着,一些奇怪的事情发生,这取决于什么类型的单子的功能在运行。

  • 如果是这样的身份单子,什么都不会发生。 monadic版本和纯版本完全一样。没有副作用。

  • 如果每个函数返回一个Maybe -something,那么如果(比方说)bar返回Nothing,整个代码块中止。一个正常的函数不能这样做。 (也就是说,在纯版本中,有没有办法来阻止foobar被调用。)所以这个版本做了一些纯粹版本不能做的事情。每个函数都可以返回值或中止块。这是一个副作用。

  • 如果每个函数都返回一个list-of-something,那么代码将执行所有可能的结果组合。再次,在纯版本中,有没有办法使任何函数执行多次不同的参数。所以这是一个副作用。

  • 如果每个功能的状态下运行单子,那么(例如)foo可以直接发送一些数据foobar,除了可以看到通过bar被传递的值。再次,你不能用纯函数做到这一点,所以这是一个副作用。

  • IO monad,你有各种有趣的效果。您可以将文件保存到磁盘(文件基本上是一个巨大的全局变量),甚至可以影响在其他计算机上运行的代码(我们称之为网络I/O)。

  • ST monad是IO monad的精简版本。它允许可变状态,但独立计算不能相互影响。

  • STM monad让多个线程可以相互通话,并且可能会导致代码执行多次,以及......您无法使用普通函数执行任何操作。

  • 继续monad让你打破人心!可以说这是可能与纯函数...

+1

我同意你赋予继续monad的“效果”。除此之外,我不在你身边。 “do”符号隐藏对>> =的调用并不会产生效果,因为如果没有这种语法糖的话,效果会同样有效,但不会隐藏>> =。事实上,它根据monad的类型做了不同的事情,这是因为monad是一个类型类。所有类型类都会发生这种情况,有效或无效。 –

+0

好吧,显然'IO','ST'和'STM'只能通过执行普通Haskell代码无法做到的低级别的东西来实现。严格地说,所有其他monad都只是纯代码被无形运行。但是*认为*是有效的计算仍然有用。在某种程度上,这只是一个观点问题。 – MathematicalOrchid

+0

同意兰花。有效的语义是Monad的面向用户的语义,Haskell程序员在实践中根据效果来思考。通过纯函数实现通常就是这个实现细节。无论如何,停止在纯粹的功能级别的表示方式上是有些武断的,当我们可以进一步研究机器代码时,尽管源代表是纯粹的,但它们具有许多可变更新。 –

10

side effect一个与它的环境可观察到的相互作用(除了计算其结果的值)。在Haskell中,我们尽力避免出现这些副作用的功能。这甚至适用于IO操作:评估IO操作时,不会执行副作用,只有在main内执行IO值中规定的操作时才会执行操作。但是,当使用与构成计算相关的抽象(如应用函子和monad)时,可以方便地区分实际值和“我们常称之为”效果“的”休息“。特别是,如果我们有f类型的kind* -> *,那么在f aa部分是“价值”,无论“剩余”是“效果”。

我故意引用了这些术语,因为没有准确的定义(据我所知),它只是一个口语定义。在某些情况下,根本没有值或多个值。例如对于Maybe,“效应”是可能没有值(并且计算被中止),对于[],“效应”是有多个(或零)值。对于更复杂的类型,这种区别可能更加困难。

“效果”和“值”之间的区别并不取决于抽象。 Functor,ApplicativeMonad只是给我们工具我们可以用它们做什么(Functor s允许修改里面的值,Applicative s允许组合效果和Monad s允许效果依赖于以前的值)。但在Monad S中的情况下,这是比较容易创造是怎么回事的心灵上的图画,因为一元行动可以“看到”以前计算的结果值,由

(>>=) :: m a -> (a -> m b) -> m b 

操作员见证:第二个函数接收到一个类型为a的值,所以我们可以想象“先前的计算有一些效果,现在有它的结果值,我们可以做些什么”。

+1

您能详细说明应用程序的“效果”吗?毕竟有一篇论文“应用程序编程与效果”,我从来没有完全理解标题(我相信我理解应用程序虽然) –

+2

@MartinDrautzburg正​​如我写的,“效果”和“值”之间的区别由实际数据给出类型,而不是我们用来操纵它的抽象。例如,对于'Maybe',“效应”总是可以中止计算,而不管我们是否使用Applicative或Monad(或其他)接口。如果你在'Maybe'中写了''f <$> a <*> b <*> c','a','b'或'c'中的任何一个都可以用Nothing来中止计算,这就是它的“效果”。 Applicative接口允许组合效果(对于'Maybe',它意味着在第一个'Nothing'时放弃),但不允许效果依赖于以前的值。 –

1

支持Petr Pudlák's answer,这里是关于更广泛的“效应”概念的起源的争论。

短语“effectful编程”在麦克布莱德的摘要显示了与帕特森的Applicative Programming with Effects,介绍应用性函子纸:

在本文中,我们将介绍Applicative函子 - 的应用性风格的抽象表征有效的编程,弱于Monad s,因此更广泛。

“效果”和“有效”出现在纸的其他一些段落中;这些出现被认为不够明显,不需要明确澄清。举例来说,这句话是由Applicative定义呈现只是后(第3页):

在每个例子中,有一种类型构造f嵌入通常的 概念的值,但支持它自己的给予含义通常应用性语言特有的方式[...]我们相应地引进Applicative类:

[的Applicative Haskell的定义]

这个类可以推广小号K [即the S and K combinators,它出现在Reader /函数Applicative实例]中,以使线程环境线程化以通常对线程效果进行线程化。

从这些报价,我们可以推断出,在这种情况下:

  • 影响是事情Applicative线程“一般”。

  • 效果与给定Applicative实例的类型构造函数相关联。

  • Monad也处理效果。

根据这些线索,我们可以追溯的“效果”这种用法至少可以追溯到Wadler's papers on monads。例如,这里是从单子6页的报价功能编程

一般而言,类型A→B的功能由类型一个 →M B的函数替换。这可以被理解为接受类型一个 的参数,并返回型b的结果,与由 中号捕获的可能的附加效果的函数。这种影响可能是对状态采取行动,产生输出,引发异常,或者你有什么。

而且从相同的纸张,第21页:

如果单子封装效果和列表形成一个单子,办列表对应于一定的效果?他们确实是这样做的,他们对应的效果是选择。可以将[a]的计算看作提供值的选择,对于列表中的每个元素都有一个值。类型a→b函数的monadic等效函数是类型a→[b]的函数。

的“对应于一定的影响”这句话的转弯这里的关键是:它关系返回到抽象的更直接的要求:

单子提供其它语言中用于模拟效果的方便框架如全局状态,异常处理,输出或非确定性。

的间距是单子可以用来表达的是,在“其他语言”,通常被编码为副作用的东西 - 那就是,作为切赫Pudlák把它放在他的答案在这里,“可观察到的与[函数]环境的交互(除了计算其结果值)“。通过转喻,这很容易导致“效果”获得第二个含义,比“副作用”更广泛 - 即通过一个类型构造函数引入的东西,这个类型构造函数是一个Monad实例。随着时间的推移,这个含义被进一步推广到涵盖其他仿函数类,如Applicative,如McBride和Patterson的工作中所见。

总之,我认为“效应”以具有在Haskell用语2个合理含义:

  • A“文字”或“绝对”的一者:效果是一个副作用;和

  • “广义”或“相对”一个:效果是一个函数上下文。

有时候,当涉及各方隐含地假定“效应”的含义不同时,可避免的术语分歧发生。另一个可能的争论点是涉及单独处理Functor时是否合法,而不是像ApplicativeMonad(我相信可以这样做,与Petr Pudlák's answer to Why can applicative functors have side effects, but functors can't?一致)这样的子类。

相关问题