Oop 函数式编程语言是如何工作的?
如果函数式编程语言不能保存任何状态,它们如何做简单的事情,比如读取用户输入?他们如何“存储”输入(或存储任何相关数据?) 例如:这个简单的C语言如何翻译成Haskell这样的函数式编程语言Oop 函数式编程语言是如何工作的?,oop,programming-languages,haskell,functional-programming,paradigms,Oop,Programming Languages,Haskell,Functional Programming,Paradigms,如果函数式编程语言不能保存任何状态,它们如何做简单的事情,比如读取用户输入?他们如何“存储”输入(或存储任何相关数据?) 例如:这个简单的C语言如何翻译成Haskell这样的函数式编程语言 #include<stdio.h> int main() { int no; scanf("%d",&no); return 0; } #包括 int main(){ 国际贸易编号; scanf(“%d”和“否”); 返回0; } (我的问题受到这篇优秀文章的启
#include<stdio.h>
int main() {
int no;
scanf("%d",&no);
return 0;
}
#包括
int main(){
国际贸易编号;
scanf(“%d”和“否”);
返回0;
}
(我的问题受到这篇优秀文章的启发:。阅读它让我更好地理解了什么是面向对象编程,Java如何以一种极端的方式实现它,函数式编程语言是如何形成对比的。)函数式编程源于lambda演算。如果你真的想了解函数式编程,请查看 这是一个“有趣”的方式来学习lambda微积分,并把你带入令人兴奋的函数编程世界 了解Lambda演算对函数式编程的帮助。 因此,LAMBDA演算是许多现实世界编程语言的基础,如LISP,Stand,ML,Haskell,. 假设我们想要描述一个函数,它向任何输入中添加三个,我们将写:
plus3 x = succ(succ(succ x))
阅读“plus3是一个函数,当应用于任何数字x时,产生x的后继数的后继数”
请注意,向任何数字添加3的函数不需要命名为plus3;名称“plus3”只是命名此函数的一个方便的缩写
(plus3x)(成功0)≡ ((λx.(suc(suc(suc x)))(suc 0))
注意,我们使用lambda符号表示函数(我认为它看起来有点像鳄鱼,我猜这就是鳄鱼蛋的起源)
lambda符号是鳄鱼(a函数),x是它的颜色。你也可以把x看作一个参数(Lambda演算函数实际上只假设有一个参数),剩下的你可以把它看作函数的主体
现在考虑抽象:
g ≡ λ f. (f (f (succ 0)))
参数f用于函数位置(在调用中)。
我们称g为高阶函数,因为它接受另一个函数作为输入。
您可以将其他函数调用f视为“egs”。
现在,利用我们创建的两个函数或“Alligators”,我们可以执行以下操作:
(g plus3) = (λ f. (f (f (succ 0)))(λ x . (succ (succ (succ x))))
= ((λ x. (succ (succ (succ x)))((λ x. (succ (succ (succ x)))) (succ 0)))
= ((λ x. (succ (succ (succ x)))) (succ (succ (succ (succ 0)))))
= (succ (succ (succ (succ (succ (succ (succ 0)))))))
RealWorld pureScanf(RealWorld world, const char* format, ...);
如果你注意到,你可以看到我们的λf鳄鱼吃了我们的λx鳄鱼,然后λx鳄鱼就死了。然后我们的λx鳄鱼在λf的鳄鱼卵中重生。然后这个过程重复,左边的λx鳄鱼现在吃掉右边的另一只λx鳄鱼
然后你可以使用这组简单的规则来设计语法,函数式编程语言就诞生了
所以你可以看到,如果你知道Lambda演算,你就会理解函数式语言是如何工作的 哈斯克尔:
main = do no <- readLn
print (no + 1)
main=do no函数式语言可以保存状态!他们通常只是鼓励或强迫你明确地这样做
例如,查看Haskell的。(一些函数式语言允许使用不纯函数。)
对于纯函数式语言,真实世界的交互通常包括在函数参数中,如下所示:
(g plus3) = (λ f. (f (f (succ 0)))(λ x . (succ (succ (succ x))))
= ((λ x. (succ (succ (succ x)))((λ x. (succ (succ (succ x)))) (succ 0)))
= ((λ x. (succ (succ (succ x)))) (succ (succ (succ (succ 0)))))
= (succ (succ (succ (succ (succ (succ (succ 0)))))))
RealWorld pureScanf(RealWorld world, const char* format, ...);
不同的语言有不同的策略将世界从程序员那里抽象出来。例如,Haskell使用monad隐藏world
参数
但是函数式语言本身的纯部分已经是图灵完备的,这意味着任何在C中可行的东西在Haskell中也是可行的。命令式语言与命令式语言的主要区别在于,它没有修改现有的状态:
int compute_sum_of_squares (int min, int max) {
int result = 0;
for (int i = min; i < max; ++ i)
result += i * i; // modify "result" in place
return result;
}
如果函数式编程语言不能保存任何状态,它们如何做一些简单的事情,比如读取用户的输入(我的意思是它们如何“存储”它),或者存储任何相关数据
正如您所知,函数式编程没有状态,但这并不意味着它不能存储数据。区别在于如果我写一个(Haskell)语句
let x = func value 3.14 20 "random"
in ...
我保证x
的值在..
中始终相同:任何东西都不可能改变它。类似地,如果我有一个函数f::String->Integer
(一个获取字符串并返回整数的函数),我可以确保f
不会修改其参数,也不会更改任何全局变量,也不会将数据写入文件,等等。正如sepp2k在上面的评论中所说,这种不可变性对于程序的推理非常有帮助:您编写的函数可以折叠、旋转和破坏您的数据,返回新的副本以便将它们链接在一起,并且您可以确保这些函数调用都不会做任何“有害”的事情。你知道x
总是x
,你不必担心有人在x
的声明和它的使用之间写了x:=foo bar
,因为这是不可能的
现在,如果我想从用户那里读取输入,该怎么办?正如肯尼特所说,这个想法是一个不纯函数是一个纯函数,它作为一个参数传递整个世界,并返回其结果和世界。当然,你不想这样做:一方面,它非常笨重,另一方面,如果我重复使用同一个世界对象会发生什么?所以这就被抽象了。Haskell使用IO类型处理它:
main :: IO ()
main = do str <- getLine
let no = fst . head $ reads str :: Integer
...
第一个允许我们讨论什么都不做的IO操作:return 3
是一个IO操作,它不查询真实世界,只返回3
。>=
操作符,发音为“bind”,允许我们运行IO操作。它从IO操作中提取值,通过函数传递值和真实世界,并返回结果IO操作。请注意,>=
强制执行我们的规则,即
main = getLine >>= \str -> let no = (fst . head $ reads str :: Integer) in ...