我想知道像Haskell这样的惰性函数式编程语言中的基本函数的确切类型是什么。
让我们说thunks被评估为弱头正常形式的对象。那么,在C?
这样的严格语言中,原始函数的类型应该是什么?我的猜测是:
primitive1 : (thunk, thunk, ...) -> thunk
primitive2 : (thunk, thunk, ...) -> object
我认为原始函数应该作为参数传递thunks,因为它们可能不需要其中的一些。但是,我不知道他们是否应该返回一个thunk或者被评估的对象,而后者必须用下面的某个函数来包装它以使它变得懒惰。
lazy : ((thunk, thunk, ...) -> object) -> ((thunk, thunk, ...) -> thunk)
答案 0 :(得分:1)
在GHC中,Haskell原语函数(有时称为PrimOp)是
使用指针(对“堆对象”)和未装箱的混合调用
类型(包括C风格的整数,双打等)。 Haskell类型系统
确保PrimOps始终获取数量,顺序和类型
他们期待的指针和未装箱的值。这一点很重要
但是要注意,如果一个原语期望指向特定类型的堆对象的指针,比如String
,
它期望一个指向堆对象的指针,它可能 是一个列表
构造函数(因为Haskell String
是一个字符列表)或一个thunk
可以计算到列表构造函数。
因此,Haskell PrimOp的“严格”类型无法区分 在thunk和非thunk之间。如果有一个原始函数 得到一个列表的长度,例如(没有),它可能有类型,使用你的符号,:
primitiveLength : (list_object) -> unboxed_int
list_object
指向 列表的指针
构造函数或可以产生列表构造函数的thunk。
这是唯一明智的做法。 PrimOp无法控制其参数是否仍然是一个thunk或者已被某些先前的计算部分(或完全!)评估,因此它必须准备好接受。
类似地,如果Haskell PrimOp 返回一个堆对象,那么该对象在技术上可能是thunk或非thunk,并且该选择对原语的“strict”类型签名没有影响。
在实践中,PrimOp返回thunk并不是很有用。在一种惰性语言中,原语被调用的事实意味着需要它的返回值。如果它返回一个thunk,那么thunk将需要立即进行评估,那么为什么要返回thunk?
(已编辑添加:)顺便说一句,上面的PrimOps并没有什么特别之处:用户定义的Haskell函数也会被指针和未装箱类型混合使用(并且它们永远不会返回thunk)。