在Haskell中实现物联网
Iota是一种非常小的“编程语言”,只使用一个组合器。我很想了解它是如何工作的,但是如果能用一种我熟悉的语言看到它的实现,那会很有帮助 我发现了一个用Scheme编写的Iota编程语言的实现。不过我在把它翻译成Haskell时遇到了点麻烦。这相当简单,但我对Haskell和Scheme都比较陌生 您将如何在Haskell中编写等效的Iota实现在Haskell中实现物联网,haskell,scheme,implementation,iota,Haskell,Scheme,Implementation,Iota,Iota是一种非常小的“编程语言”,只使用一个组合器。我很想了解它是如何工作的,但是如果能用一种我熟悉的语言看到它的实现,那会很有帮助 我发现了一个用Scheme编写的Iota编程语言的实现。不过我在把它翻译成Haskell时遇到了点麻烦。这相当简单,但我对Haskell和Scheme都比较陌生 您将如何在Haskell中编写等效的Iota实现 (let iota () (if (eq? #\* (read-char)) ((iota)(iota)) (lambda (c) ((
(let iota ()
(if (eq? #\* (read-char)) ((iota)(iota))
(lambda (c) ((c (lambda (x) (lambda (y) (lambda (z) ((x z)(y z))))))
(lambda (x) (lambda (y) x))))))
我一直在自学这些东西,所以我真的希望我能做到以下几点 正如n.m.提到的,Haskell是打字的,这一事实对这个问题非常重要;类型系统限制可以形成什么表达式,特别是lambda演算的最基本类型系统禁止自应用,这最终会给您一种非图灵完整语言。图灵完整性作为语言的一个额外功能添加到基本类型系统之上(a
fix::(a->a)->a
运算符或递归类型)
这并不意味着你不能在Haskell中实现这一点,而是说这样的实现不会只有一个操作符
方法#1:实现,并添加一个fix
功能:
iota' :: ((t1 -> t2 -> t1)
-> ((t5 -> t4 -> t3) -> (t5 -> t4) -> t5 -> t3)
-> (t6 -> t7 -> t6)
-> t)
-> t
iota' x = x k s k
where k x y = x
s x y z = x z (y z)
fix :: (a -> a) -> a
fix f = let result = f result in result
现在您可以根据iota'
和fix
编写任何程序。解释它是如何工作的有点复杂。(编辑:请注意,iota'
与原始问题中的λx.x S K
不同;它是λx.x K S K
,也是图灵完备的。iota'
程序将不同于iota
程序。我尝试了iota=λx.x S K
定义Haskell中的初始化;它会进行类型检查,但当您尝试k=iota(iota(iota-iota))
和s=iota(iota(iota-iota)))
时,会出现类型错误。)
方法#2:可以使用以下递归类型将非类型lambda演算表示嵌入Haskell中:
newtype D = In { out :: D -> D }
D
基本上是一种类型,其元素是从D
到D
的函数。我们有In::(D->D)->D
将D->D
函数转换为普通的D
,而out::D->(D->D)
则做相反的事情。因此,如果我们有x::D
,我们可以通过执行out x::D
来自行应用它
给我这个,现在我们可以写:
iota :: D
iota = In $ \x -> out (out x s) k
where k = In $ \x -> In $ \y -> x
s = In $ \x -> In $ \y -> In $ \z -> out (out x z) (out y z)
这需要In
和out
发出一些“噪音”;Haskell仍然禁止您将D
应用于D
,但我们可以使用In
和out
来解决此问题。实际上,您不能对D
类型的值做任何有用的事情,但可以围绕相同的模式设计一个有用的类型
编辑:物联网基本上是
λx.x S K
,其中K=λx.λy.x
和S=λx.λy.λz.x z(y z)
。即,iota采用双参数函数,并将其应用于S和K;因此,通过传递一个返回其第一个参数的函数,可以得到S,通过传递一个返回其第二个参数的函数,可以得到K。因此,如果可以使用iota编写“返回第一个参数”和“返回第二个参数”,则可以使用iota编写S和K。但是,你也可以在交易中得到图灵完全性。事实证明,您可以使用iota编写必要的选择器函数,因此iota足以满足图灵完整性的要求
因此,这将理解iota的问题简化为理解SK演算。Haskell中没有等效的实现。这样的实现不会进行类型检查。当然,可以使用不同的策略编写实现。是的,我知道它不会进行类型检查。我想我被绊倒的部分是理解((iota)(iota))在这个实现中所做的事情。我无法理解方法2,但我开始掌握方法1。您愿意更详细地解释一下吗?fix操作符到底是如何工作的?
fix
是一个函数,它基本上将无界递归引入到缺少它的语言中。如果您听说过Y组合器,fix
在Haskell中是等效的。简短的解释是,fixf=f(f(f(f…))
(一个无限的f
)应用程序塔);由于在Haskell中,f
可能是懒惰的,f
可以选择返回一个值,而不使用f
(基本情况)或使用f(f(f(f…))
堆栈(递归情况)。关于修复
:通常可以转换递归函数f=λx。。。f y…
添加一个表示递归情况的额外参数,并对结果进行修正:f=fix(λrec x……rec y…
。在第一种方法中,您编写了iota x=x k s k
,在第二种方法中-“iota基本上是λx.x s k
”。那可能是打字错误吗?@威利斯:不,不是打字错误。显示了两种可能的定义方式,这导致了基于物联网的s
和k
的不同定义。但是,出于某种原因,如果在Haskell中使用λx.x S K
版本,而该版本进行了类型检查,则相关的S
和K
定义不起作用。