Functional programming 一切都可以建模为函数吗? 让我们考虑一个例子:我想打开/关掉一个灯泡。在C语言中,我可以写: struct lightbulb { int is_turned_on; /* from 1 to 10 */ int light_intensity; };

Functional programming 一切都可以建模为函数吗? 让我们考虑一个例子:我想打开/关掉一个灯泡。在C语言中,我可以写: struct lightbulb { int is_turned_on; /* from 1 to 10 */ int light_intensity; };,functional-programming,Functional Programming,每当我想打开或关闭灯泡时,我都会将是否打开设置为1,并通过将灯光强度从1(最暗)设置为10(最亮)将其亮度设置为1 如何在函数式编程中实现同样的功能?我想我必须创建一个列表来保存这些值,创建一个函数ON和OFF“打开/关闭”灯泡,以及一个函数来返回灯泡的光强度。每次调用该函数时,都会返回一个新灯泡: (defun turn-on() '(1 0)) (defun turn-off() '(0 0)) (defun light-intensity (x) `(0 ,(eval x)))

每当我想打开或关闭灯泡时,我都会将
是否打开
设置为1,并通过将
灯光强度
从1(最暗)设置为10(最亮)将其亮度设置为1

如何在函数式编程中实现同样的功能?我想我必须创建一个列表来保存这些值,创建一个函数
ON
OFF
“打开/关闭”灯泡,以及一个函数来返回灯泡的光强度。每次调用该函数时,都会返回一个新灯泡:

(defun turn-on()
  '(1 0))
(defun turn-off()
  '(0 0))
(defun light-intensity (x)
  `(0 ,(eval x)))
我可以看到,像光强度这样的函数是一个连续函数,类似于线性函数。无论我们为每个x传递相同的参数
x
多少次,它的计算结果都是相同的。每个功能的结果是一个具有不同状态的新灯泡

问题是,我怎样才能保持状态?显然,我必须通过变量将它存储在我记忆中的某个地方

更新:我通过

数据项如何持久化?

在堆栈上。在顺序批处理程序中,数据被初始化并 在顶级函数中转换。在一个长期存在的程序中,比如 服务器,递归调用顶级循环函数,传递 从一个呼叫到下一个呼叫的全局状态

每次调用函数时,我还必须创建一个新对象(列表),如何销毁以前的旧对象

通过
defparameter
setf
对变量进行变异不是更有效、更简单吗?想象一下,如果它不是一个灯泡,而是一个包含更多信息的更复杂的物体?如何将其建模为函数


我问的是如何用纯泛函有效地处理状态 编程,而不需要另一个副本,只是为了使其具有“参考性” 透明度“

在函数式编程中,只要语言支持线性类型,就可以有效地处理状态。也就是说,每个可变单元都被赋予一个线性类型,类型检查器确保任何线性类型的变量都不会根据程序员的意愿被丢弃或复制。例如,这是不允许的:

val x = make_reference (5) // [x] is a mutable cell
val y = x
val res = !x + !y // the syntax [!x] is for reading a value of a cell
这是不允许的,因为[x]有一个线性类型,并且线性类型的值不能复制(这基本上就是我们在下一行将[y]绑定到[x]时所做的)。这种复制也称为“别名”(或“共享”),而别名又使状态操纵程序更难推理(例如,通过破坏引用透明性)。因此,线性类型限制了别名,这有助于对程序进行推理。大多数情况下,具有线性类型的程序在引用上是透明的,并且与纯函数程序保持一些相似性

以下是ATS中使用线性类型处理(可变)状态的示例

typedef灯泡(b:bool)=@{是否打开=bool b,灯光强度=intBtw(1,10)}
fn灯泡{b:bool}(状态:bool b,强度:intBtw(1,10)):灯泡b=
@{是否已打开状态,灯光强度=强度}
//[&T1>>T2]符号表示该函数期望被给定
//T1类型的术语,然后在退出时,该术语的类型将
//换成T2。
//在我们的例子中,函数期望灯泡打开或关闭,
//但在出口处,灯泡将被关闭。
fn灯泡打开{b:bool}(x:&灯泡b>>灯泡为真):无效=
x、 _是否已打开:=真
fn灯泡变化强度{b:bool}(x:&灯泡b,y:intBtw(1,10)):无效=
x、 光照强度:=y
实现main()=let
var灯泡=灯泡品牌(错误,5)
val()=灯泡打开(灯泡)
val()=灯泡变化强度(灯泡,3)
在里面
printf(“强度现在为:%d\n”,@(灯泡亮度))
结束
问题是,我怎样才能保持状态?显然,我必须通过变量将它存储在我记忆中的某个地方

我认为您是从命令式的角度来看待函数式编程,这种情况经常发生,并且可能会令人困惑。在函数式编程中,它不是将程序表示为修改状态的一系列步骤(例如,通过设置变量),而是表示为一组相互依赖的数学样式函数,每个函数只包含一个表达式。因为在函数中包含多行的唯一原因是修改状态,在纯函数编程中,所有函数都是一行程序;这意味着代码作为一系列级联函数调用运行。程序往往更像是问题的描述,而不是一步一步的说明

每次调用函数时,我还必须创建一个新对象(列表),如何销毁以前的旧对象

我认为所有函数式编程语言都使用垃圾收集。更少的副作用和内存别名意味着当内存不再被使用时,计算起来更简单

通过defparmeter和setf对变量进行变异不是更有效、更简单吗?想象一下,如果它不是一个灯泡,而是一个包含更多信息的更复杂的物体?如何将其建模为函数


我不知道您在问什么。

您的C代码和通用Lisp代码都不正确。在C语言中,不能在
struct
声明中指定字段。在Lisp中不能应用
0
。我不明白你在问什么。。。。可变数据不是真正的函数式编程。哦,我忘了。我本来打算写一个主函数,但不知怎么的,我决定不写它,并把它和结构声明混在一起。我会修好的。但是关于Lisp代码,这就是我所理解的。我学习了CommonLisp一段时间,而不是Scheme。我想问的是如何用纯函数式编程有效地处理状态,而不需要另一个副本
typedef lightbulb (b: bool) = @{is_turned_on= bool b, light_intensity= intBtw (1, 10)}

fn lightbulb_make {b:bool} (state: bool b, intensity: intBtw (1, 10)) :<> lightbulb b =
  @{is_turned_on= state, light_intensity= intensity}

// The [&T1 >> T2] notation means that function expects to be given
// a term of type T1, and then on exit, the type of the term will
// change to T2.
// In our case, the function expects a lightbulb either turned on or off,
// but on exit, the lightbulb will be turned off.
fn lightbulb_turn_on {b:bool} (x: &lightbulb b >> lightbulb true) :<> void =
  x.is_turned_on := true

fn lightbulb_change_intensity {b:bool} (x: &lightbulb b, y: intBtw (1, 10)) :<> void =
  x.light_intensity := y

implement main () = let
  var bulb = lightbulb_make (false, 5)
  val () = lightbulb_turn_on (bulb)
  val () = lightbulb_change_intensity (bulb, 3)
in
  printf ("intensity is now: %d\n", @(bulb.light_intensity))
end