给定Haskell类型签名,是否可以自动生成代码?

时间:2012-04-18 08:39:33

标签: haskell types

标题中的内容。如果我写一个类型签名,是否可以通过算法生成一个具有该类型签名的表达式?

似乎有可能做到这一点。我们已经知道,如果类型是库函数类型签名的特例,Hoogle可以通过算法找到该函数。另一方面,许多与一般表达有关的简单问题实际上是无法解决的(例如,不可能知道两个函数是否做同样的事情),所以这就是其中之一几乎不可信。

一次问几个问题可能是不好的形式,但我想知道:

  • 可以吗?

  • 如果是,怎么做?

  • 如果没有,是否有可能出现限制的情况?

  • 两个不同的表达式很可能具有相同的类型签名。你能计算出所有吗?或者甚至一些吗?

  • 有没有人有真正做这个东西的工作代码?

4 个答案:

答案 0 :(得分:33)

Djinn为Haskell类型的受限子集执行此操作,对应于一阶逻辑。但它无法管理需要递归实现的递归类型或类型;因此,例如,它无法编写(a -> a) -> a类型的术语(fix的类型),这对应于命题“如果 a 暗示 a ,然后 a “,这显然是假的;你可以用它来证明什么。实际上,这就是fix引起⊥。

的原因

如果你允许fix,那么写一个程序给出任何类型的术语是微不足道的;该程序只需为每种类型打印fix id

Djinn主要是玩具,但它可以做一些有趣的事情,比如MonadReader的{​​{1}}实例,给出Cont和{return的类型{1}}。您可以通过安装djinn软件包或使用lambdabot进行试用,并将其集成为(>>=)命令。

答案 1 :(得分:14)

Oleg上的{p> okmij.org已实现此目的。有一个简短的介绍here,但literate Haskell source包含详细信息和流程说明。 (我不确定这与Djinn的力量如何对应,但这是另一个例子。)


有些情况下没有独特功能:

fst', snd' :: (a, a) -> a
fst' (a,_) = a
snd' (_,b) = b

不仅如此;有些情况下有无数的功能:

list0, list1, list2 :: [a] -> a
list0 l = l !! 0
list1 l = l !! 1
list2 l = l !! 2
-- etc.

-- Or 
mkList0, mkList1, mkList2 :: a -> [a]
mkList0 _ = []
mkList1 a = [a]
mkList2 a = [a,a]
-- etc.

(如果您只想要全部功能,请将[a]视为限制为list0list1等的无限列表,即data List a = Cons a (List a)

实际上,如果你有递归类型,任何涉及这些类型的类型都对应于无数个函数。但是,至少在上面的例子中,有相当数量的函数,因此可以创建一个包含所有函数的(无限)列表。但是,我认为类型[a] -> [a]对应于无数个无限数量的函数(再次将[a]限制为无限列表),因此您甚至无法枚举所有函数!

(摘要:有些类型对应于有限的,可数无限且无数无限的函数。)

答案 2 :(得分:7)

这通常是不可能的(对于像Haskell这样甚至没有强规范化属性的语言),并且只能在某些(非常)特殊情况下(对于更受限制的语言),例如当一个codomain类型具有唯一的构造函数(例如,函数f :: forall a. a -> ()可以唯一确定)。为了将给定签名的一组可能定义减少到仅具有一个定义的单例集需要给出更多限制(例如,以附加属性的形式,仍然很难想象如果没有给出它将如何有用一个使用的例子。)

从(n-)分类的观点来看,类型对应于对象,术语对应于箭头(构造函数也对应于箭头),而函数定义对应于2个箭头。这个问题类似于是否可以通过仅指定一组对象来构造具有所需属性的2类别的问题。这是不可能的,因为你需要一个明确的箭头和两个箭头构造(即编写术语和定义),或演绎系统,它允许使用一组特定的属性(仍然需要明确定义)推导出必要的结构。


还有一个有趣的问题:给定一个ADT(即Hask的子类别),可以自动派生Typeable,Data(是的,使用SYB),Traversable,Foldable,Functor,Pointed, Applicative,Monad等(?)。在这种情况下,我们有必要的签名以及其他属性(例如,monad定律,尽管这些属性不能在Haskell中表达,但它们可以用依赖类型的语言表示)。有一些有趣的结构:

http://ulissesaraujo.wordpress.com/2007/12/19/catamorphisms-in-haskell

显示了可以对ADT列表执行的操作。

答案 3 :(得分:3)

问题实际上相当深刻,我不确定答案,如果你问的是Haskell类型的全部荣耀,包括类型族,GADT等等。

您要问的是程序是否可以通过展示这样的值来自动证明任意类型居住(包含值)。一个叫库里 - 霍华德通信的原则说,类型可以被解释为数学命题,如果命题是建设性可证明的,那么类型就有人居住。所以你问是否有一个程序可以证明某类命题是定理。在像Agda这样的语言中,类型系统足以表达任意数学命题,并且通过哥德尔的不完备性定理证明任意的数学命题是不可判定的。另一方面,如果你下降到(比方说)纯粹的Hindley-Milner,你会得到一个更弱的(我认为)可判定的系统。使用Haskell 98,我不确定,因为类型类应该能够与GADT相当。

使用GADT,我不知道它是否可以判定,但也许这里有一些知识渊博的人会马上知道。例如,有可能将给定图灵机的暂停问题编码为GADT,因此如果机器停止,则存在该类型的值。在这种情况下,可居住性显然是不可判定的。但是,即使是类型族,也许这种编码不太可能。我目前对这个主题的流利程度不够,因为无论如何,这对我来说都是显而易见的,尽管如我所说,也许其他人知道答案。

(更新:)哦,对我的问题进行了更简单的解释:你可能会问每个Haskell类型是否有人居住。答案显然不是。考虑多态类型

a -> b

没有该签名的功能(不计算unsafeCoerce,这会使类型系统不一致)。