我对Haskell很新,我创建了一个高阶函数:
forAll f ls ls2 = all (`f` ls) ls2
我需要指定类型,但我对函数f的类型有疑问:
GHCi说:
forAll :: (a -> t -> Bool) -> t -> [a] -> Bool
但不应该是这样的吗?
forAll :: (a -> t) -> t -> [a] -> Bool
感谢。
答案 0 :(得分:5)
不,因为all
的类型为
all :: (a -> Bool) -> [a] -> Bool
f
必须返回Bool
。由于
(`f` ls)
(\a -> a `f` ls)
flip f ls
f
必须使用列表元素ls
,并生成Bool
。制作它的类型
f :: a -> t -> Bool
ls :: t
和ls2 :: [a]
。
答案 1 :(得分:2)
让我们检查您怀疑此功能必须采用的类型。
类型(a -> t)
表示给定一些a
我们可以生成t
。我们在a
s a
列表中有一些[a]
,因此我们可以假设t
类型为[t]
。此外,我们又传递了另一个t
,我们可以将其添加到其他[t]
中。
现在,我称之为a
和t
,因为我们真的不知道他们的实际类型是什么。也就是说,我们知道我们的目标是什么:我们必须生成Bool
。
因此,我们函数中的某个位置必须是将t
的{{1}}转换为[t]
的方法。Bool
。我们可以用length ts > 3
这样的方法做到这一点,但我怀疑这是你正在寻找的东西。
GHC为您提供的功能类型看起来有点不同。它声明我们可以将a
和t
放在一起Bool
(类型为(a -> t -> Bool)
)。由于我们有一个a
的列表,只要我们有t
的来源,我们就可以将它们中的每一个一个接一个地提供给这个函数。由于我们只有一个t
,我们每次都需要使用它。总而言之,这给了我们一堆Bool
s,[Bool]
甚至。这正是我们正在寻找的东西,因为我们希望使用[Bool]
将Bool
的列表压缩为单个all
。< / p>
我对这种类型的叙述进行了阐述 - 在这里我们讨论了具有和想要价值的功能,比如你和你的程序之间的交换游戏 - 是一种非常常见的推理类型的方法你的程序你可以经常进行这种探索,为你所构建的程序类型提供很多理由。
归根结底,GHC始终是&#34;对&#34;关于您询问的特定值的类型 - 这是Hindley Milner类型系统的优势。尝试检查GHC经常推断出的函数类型,看看GHC是否已经推断出您错过的类型叙述的一些细节。
(顺便说一句,我提到的那个叙述,很明显,也就是说,#34; game semantics of programs&#34;它也出现在证明和逻辑中。那里有更深的关系如果你决定遵循它。)