了解Haskell的RankNTypes

在通过GHC扩展工作的过程中,我遇到了哈斯克尔学院的RankNTypes ,它有以下例子:

main = print $ rankN (+1)

rankN :: (forall n. Num n => n -> n) -> (Int, Double)
rankN f = (f 1, f 1.0)

该文章为rankN提供了另一种类型:

rankN :: forall n. Num n => (n -> n) -> (Int, Double) 

对不同点的解释是:“后一个签名需要从n到n的函数,对于某些Num n;前一个签名需要从n到n的函数,用于每个Num n。”

我可以理解,前一种类型需要签名才能成为括号内或更一般的内容。 我不明白后面的签名是否需要函数n -> n来表示“一些Num n ”的解释。 有人可以详细说明吗? 你如何“读”这个前签名,使其听起来像是什么意思? 是后者的签名相同,只是Num n => (n -> n) -> (Int, Double) ,而不需要forall


在正常情况下(所有forall n. Num n => (n -> n) -> (Int, Double) ),我们先选择一个n然后提供一个函数。 所以我们可以传入Int -> IntDouble -> DoubleRational -> Rational等类型的函数。

在等级2的情况下( (forall n. Num n => n -> n) -> (Int, Double) ),我们必须在知道n之前提供函数。 这意味着函数必须适用于任何n ; 我没有列出前例的例子。

我们需要这样的代码,因为传入的函数f应用于两种不同类型: IntDouble 。 所以它必须为他们两个工作。

第一种情况是正常的,因为这是默认情况下类型变量的工作原理。 如果你没有一个forall可言,你的类型的签名相当于在一开始就拥有它。 (这被称为prenex形式。)所以Num n => (n -> n) -> (Int, Double)隐含地与所有forall n. Num n => (n -> n) -> (Int, Double)相同forall n. Num n => (n -> n) -> (Int, Double) forall n. Num n => (n -> n) -> (Int, Double)

什么类型的函数适用于任何n ? 这完全是forall n. Num n => n -> n forall n. Num n => n -> n


你如何“读”这个前签名,使其听起来像是什么意思?

你可以阅读

rankN :: (forall n. Num n => n -> n) -> (Int, Double)

作为“rankN采用参数f :: Num n => n -> n ”并且返回(Int, Double) ,其中f :: Num n => n -> n可以被读为“对于任何数字类型nf可以拿n并返回n “。

排名第一的定义

rank1 :: forall n. Num n => (n -> n) -> (Int, Double)

然后读为“对于任何数字类型nrank1接受参数f :: n -> n并返回(Int, Double) ”。

是后者的签名相同,只是Num n => (n -> n) -> (Int, Double) ,而不需要forall

是,通过默认所有forall s的隐式地放置在最外面的位置(导致秩-1型)。


rankN情况f必须是一个多态函数,其是适用于所有的数字类型n

rank1情况下,只需要为单个数字类型定义f

这里有一些代码说明了这一点:

{-# LANGUAGE RankNTypes #-}

rankN :: (forall n. Num n => n -> n) -> (Int, Double)
rankN = undefined

rank1 :: forall n. Num n => (n -> n) -> (Int, Double)
rank1 = undefined

foo :: Int -> Int  -- monomorphic
foo n = n + 1

test1 = rank1 foo -- OK

test2 = rankN foo -- does not type check

test3 = rankN (+1) -- OK since (+1) is polymorphic

更新

回复@ helpwithhaskell在评论中的问题......

考虑这个功能:

bar :: (forall n. Num n => n -> n) -> (Int, Double) -> (Int, Double)
bar f (i,d) = (f i, f d)

也就是说,我们将f应用于Int和Double。 没有使用RankNTypes,它不会输入check:

-- doesn't work
bar' :: ??? -> (Int, Double) -> (Int, Double)
bar' f (i,d) = (f i, f d)

???以下签名都不适用于:

Num n => (n -> n)
Int -> Int
Double -> Double
链接地址: http://www.djcxy.com/p/7529.html

上一篇: Understanding Haskell's RankNTypes

下一篇: Haskell, GHC 8: dynamically load/import module