Mar*_*cel 16 functional-programming elm
import Keyboard
main = lift asText (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
Run Code Online (Sandbox Code Playgroud)
foldp 定义为:
Signal.foldp : (a -> b -> b) -> b -> Signal a -> Signal b
Run Code Online (Sandbox Code Playgroud)
在我看来:
presses仅0在第一次评估时mainmain,似乎初始值presses是函数的结果(a -> b -> b),或者(\dir presses -> presses + dir.x)在示例中,是在先前的评估中.如果确实如此,那么这不是违反函数式编程原则,因为main现在维持内部状态(或者至少foldp是这样)吗?
当我foldp在代码中的多个位置使用时,这是如何工作的?它是否保留多个内部状态,每次使用一个状态?
我看到的唯一另一种选择是foldp(在示例中)从0开始计数,也就是说,每次评估它,并以某种方式折叠由提供的整个历史记录Keyboard.arrows.在我看来,这非常浪费,并且肯定会导致长时间运行时出现内存异常.
我在这里错过了什么吗?
Apa*_*hka 20
是的,foldp保持一些内部状态.保存整个历史将是浪费而且没有完成.
如果foldp在代码中多次使用,执行不同的操作或具有不同的输入信号,则每个实例将保持其自己的本地状态.例:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
minus = (foldp (\dir presses -> presses - dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus minus
Run Code Online (Sandbox Code Playgroud)
但是如果你使用foldp的结果信号两次,只有一个foldp实例将在你编译的程序中,结果的变化只会在两个地方使用:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus plus
Run Code Online (Sandbox Code Playgroud)
如果确实如此,那么这不是违反函数式编程原则,因为main现在维持内部状态(或者至少
foldp是这样)吗?
函数式编程没有一个每个人都使用的伟大的规范定义.有许多函数式编程语言的例子允许使用可变状态.其中一些编程语言向您显示类型系统中的值是可变的(您可以看到Haskell的State a类型,但它实际上取决于您的观点).
但是什么是可变状态?什么是可变值?它是程序内部的一个值,是可变的.也就是说,它可以改变.在不同的时间它可以是不同的东西.啊,但我们知道榆树如何随着时间的推移而改变价值观!那是一个Signal.
所以Signal在Elm中确实是一个可以随时间变化的值,因此可以被视为变量,可变值或可变状态.只是我们非常严格地管理这个值,只允许对Signals 进行一些精心选择的操作.这样的a Signal可以基于Signal程序中的其他s,或者来自图书馆或来自外部世界(想想输入等Mouse.position).谁知道外界怎么想出那个信号呢!所以允许你自己的Signals基于s的过去值Signal实际上是可以的.
你可以看到Signal围绕可变状态的安全包装.我们假设来自外部世界的信号(作为您的程序的输入)是不可预测的,但是因为我们有这个安全包装器只允许提升/采样/过滤器/折叠,所以您编写的程序是完全可预测的.包含和管理副作用,因此我认为它仍然是"函数式编程".
Kar*_*ldt 10
您将实现细节与概念细节混淆.每种函数式编程语言最终都会被转换为汇编代码,这显然是必不可少的.这并不意味着你不能在语言水平上拥有纯洁.
不要认为main被重复评估,每次都会返回不同的结果.A Signal在概念上是一个无限的值列表. main将无限的键盘箭头列表作为输入,并将其转换为无限的元素列表.给定相同的箭头列表,它将始终返回完全相同的元素列表,没有副作用.在这个抽象层次上,它是一个纯粹的功能.
现在,碰巧我们只对序列的最后一个元素感兴趣.这允许在实现中进行一些优化,其中之一是存储累积值.重要的是,实施是参考透明的.从语言的角度来看,你得到了完全相同的答案,就好像你存储了整个序列一样,并且每次将值添加到结尾时都从头开始重新计算.给定相同的输入,您获得相同的输出.唯一的区别是存储空间和执行时间.
换句话说,函数式编程的整个想法不是消除状态跟踪,而是将其从程序员的范围中抽象出来.程序员可以在理想的世界中发挥作用,而编译器和运行时从属于可变状态的下水道,可以为我们其他人提供理想的世界.
| 归档时间: |
|
| 查看次数: |
2083 次 |
| 最近记录: |