繁体   English   中英

Lambda表达式在Scheme中是单子吗?

[英]Lambda expressions as monads in Scheme?

我在网上阅读了一些文档,这些文档试图为Scheme程序员介绍monad的概念。 核心思想是在非命令式编程中,monad用于表示“计算流”,即强制执行表达式的顺序求值。 然后让我震惊:既然lambda表达式的主体是按顺序求值的,那么人们是否应该理解Monad在Scheme中是多余的? 在其他语言(例如,Haskell或ML)中,lambda主体的评估是否有所不同?

顺序评估

因此,表达式的顺序求值不是monad的特征,而是函数的特征 从您写出f (gx) (Haskell)或(f (gx)) (方案)的那一刻起,您就已经将g排序为发生在f之前。 相反,在Haskell中,我们使用(then fg)(bind f (lambda (x) (make-g x)))类的序列运算符来执行此操作,但是您可以根据需要执行此操作。

困惑是:monad至少在Haskell中带有通用表示法 ,并且该通用表示法将语句按命令顺序放置。 从Scheme的角度来看,这是一个宏do ,它重写:

(do
    (put-string "Hey, what's your name?")
    (into x get-line)
    (put-string (string-append "Hi, " x "!")))

(then 
    (put-string "Hey, what's your name?")
    (bind get-line (lambda (x) 
        (put-string (string-append "Hi, " x "!")))))

请注意,lambda被“展平”并替换为一些新符号“ into”。 (实际上,在Haskell中,我们会说“ from”,但这是一个中缀运算符,而不是前缀运算符。)

什么是单子

那么,什么单子呢? 好吧,首先,让我们定义它们的词性:单子形容词 ,就像形容词“ blue”一样。 我可以有蓝色的马车或蓝色的车轮。 Monad是函子 ,这意味着从旅行车到其轮子的功能,我可以为您提供从蓝色旅行车到其蓝色轮子的功能。 因此功能可以“在其下操作”。 但是monad具有两个特殊属性。 首先,我们有一个只适用于“蓝色”的想法,如果我们使该想法变得异常抽象和形而上的话 :形容词必须能够应用于语言中的任何值 因此,您不仅拥有蓝色的旅行车和蓝色的轮子,而且拥有蓝色的功能和打印“ Hello,World!”的蓝色程序。 到屏幕上,蓝变一切。 第二个形容词在某种意义上必须是可压缩的,因为给定一个蓝色的蓝色旅行车,您可以给我一个蓝色的旅行车。

做到这一点的形容词是“可为空...”。 您始终可以获取任何值,并根据该值生成一个新的可为空的值:只需开始接受和检测空值! 如果您使用的是默认情况下不能为空的静态类型语言,那么这很重要。 这个形容词是一个函子:给定一个函数,我们只是将null转换为null,然后使用该函数进行任何其他转换。 这是可压缩的,因为如果我们有一个“可为空的可为空字符串”可简化为可为空的字符串:将“ null”和“ not-null null”值分别设置为“ null”,将“ not-null not-null字符串”设置为“非空字符串”。 最后,要将任何字符串表示为可为空的字符串,请将其转换为“非空字符串”。 这称为Maybe monad。 实际上,这是Either y monad的特殊情况,可以容纳y

这样做的另一个形容词是“ ...的列表”。 要在形容词下应用功能,请将其应用到列表的所有成员。 要将列表列表压缩为列表,请串联其元素。 要从任何x创建x的列表,请给我返回一个元素列表。 这称为“列表单子”。 这种写法很像写列表推导,实际上与Clojure换能器是同构的,因此您可以免费获得地图和过滤器。

这样做的另一个形容词是“从s到s和a ...的函数”。 要从任何x创建其中之一,只需将传入状态与x配对。 要应用功能,只需将其应用到输出对的相应一侧即可。 十分简单。 最后,如果您遇到了复杂的s -> (s, s -> (s, a))情况,则通过将传入的s馈送给被卷积的函数来构造s -> (s, a) ,并取出出现的s然后将其馈送到其中的s -> (s, a)中。 这为您提供了您需要返回的(s, a) 这被称为“ State s monad”,因为您可以将“ s”设想为类型化状态。

执行此操作的另一个形容词是“返回a的程序”。 如果您有一个int,我们可以构建一个不执行任何操作并返回该int的程序。 如果您有一个将int和函数从int返回到其他函数的程序,我们可以执行该程序,然后将该函数应用于程序的输出。 最后,如果您拥有“一个程序返回一个程序,该程序返回一个int”,则只需形成一个程序,该程序运行外部程序以计算内部程序,然后运行内部程序。 这称为IO x monad。 (与承诺类似:承诺的x与承诺的x没有太大区别。)

您会看到这是一个非常广泛的模式,并且并不总是清楚地涉及“序列”。

与Haskell的比较方案

一旦了解了Haskell通过将程序作为值并将它们组合在一起来描述了其所有I / O操作,您就会意识到,基本上我们是通过成为一种宏语言来进行功能性I / O的 宏语言本身不会执行任何 I / O,但是您可以使用它来构造为您执行I / O的程序。 您将它们输入到编译器中,然后编译器将生成实际程序,该程序可以执行您想要的操作。 口译员会获得更多选择,因为口译员需要说“如果我看到一个不是程序的值,我将尝试打印该值;如果我看到一个不是程序的值, 我将尝试运行该程序,然后打印出来。” 这意味着命令提示符下的语法与文件中的语法略有不同。

一旦了解了Haskell是我们在构建程序即价值的元编程环境后,您将了解Haskell如何执行功能性I / O,并且您会看到“ monads”的可编程语法是元元编程设计。 这种设计比宏(在Haskell中也有它;它被称为“ Template Haskell”)要复杂得多,但是可以在很多有用的情况下完成工作。 从本质上讲,这是关于在某种程度上重载“ a; b; c; d”意味着要依赖于a,b,c和d类型的(通用)最外面的形容词。 对于I / O,它的意思是“先执行a,然后执行b,然后...”; 对于状态,它的意思是“将a产生的状态放入b,然后b产生的状态放入c,然后...”; 对于nullable来说,它的意思是“执行a,如果不是null,则使用它执行b,如果不是null,则使用它执行c ...”。 对于列表,它是构成列表的笛卡尔乘积,“以所有方式配对所有内容”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM