RankNTypes中的约束

时间:2015-07-09 03:41:30

标签: haskell types

以下功能不会检查。

test1 :: forall x. (Show x => x) -> String
test1 = show

这是因为最后->无法访问约束。 (这可能不是正确的术语,但希望它有意义。)我一直试图找到类似于上述类型签名的用法,其中最终->没有有权访问约束。但我无法想到任何例子。

所以我的问题是:是否有一种情况,我们在类型签名中设置约束是否有用,最终->无法访问?

请注意,test1与下面的排名2功能不同。

test2 :: (forall x. Show x => x) -> String
test2 = show

我对第一种情况感兴趣,而不是这种情况。 RankNTypes在标题中的原因是因为需要启用该扩展程序才能为test1创建类型签名。

2 个答案:

答案 0 :(得分:3)

将类约束视为推断的函数参数是有用的,因为它们对GHC Core中的函数和函数应用程序感到厌恶。

让我们去讨论这个类型:

newtype ShowDict a = ShowDict (a -> String)
test1 :: forall x. (ShowDict x -> x) -> String

或更简单:

test1 :: forall x. ((x -> String) -> x) -> String

这种类型并不是很有用。通过参数化,它的实现必须是返回一些字符串的常量函数。

使用原始的非desugared类型,我们甚至无法对(Show x => x)参数执行任何操作,因为我们的普遍量化{{{}没有任何Show字典。{ 1}}。

  

所以我的问题是:是否存在我们有用的情况   最终的类型签名中的约束 - >没有访问权限   到?

这有点含糊不清,但我可以论证以下内容:形式x的函数参数类型(可能在外部范围内量化(c x => t))在Haskell中永远不会有意义。

类的一致性意味着每种类型最多只有一个实例,因此x上的抽象不会产生任何计算差异。如果没有c x,那么(desugared)函数永远不会被应用,但是如果我们已经知道有一个唯一的c x,那么为什么要依赖它?

答案 1 :(得分:2)

并不是说您无法访问它,而是对类型实例化的控制被颠倒了:使用rank-2类型,您可以更改谁选择类型

在您的示例中,test2函数可以选择其参数的类型。所以,例如,这编译:

test2 :: (forall x. Show x => x) -> String
test2 a = show (a :: Char)

这是因为参数a对于作为Show实例的所有类型必须完全符合。因此,我们永远无法调用test2,因为我们永远无法提供可以采用Show实例的所有可能类型的值。

请注意我们写过

test2 :: Show x => x -> String
test2 a = ...

test2来电者可以选择a的类型,test2Show的所有实例必须有效的example :: (forall x. Show x => x -> Int) -> Int example f = 10 * f True

让我们看一个稍微有用的例子:

example

我们再次看到,我们(即x)可以选择Bool类型变量所代表的类型(实例化该类型变量为某种类型)。在这里,我们选择ghci> example (length . show) 40 类型。以下是您可以调用此函数的方法:

example2 :: (forall x. [x] -> [x]) -> [Int]
example2 f = f [1, 2, 3]

这是另一个例子:

ghci> example2 reverse
[3,2,1]

我们可以在列表上给它任何函数,只要该函数不关心该列表中的实际值。由于函数不知道这些值的类型,因此无法以任何方式检查它们(此属性称为parametricity)。

所以,我们可以这样做:

ghci> let addOne :: Int -> Int
   |>     addOne a = a + 1
   |> 
ghci> example2 (map addOne)

<interactive>:33:15:
    Couldn't match type ‘x’ with ‘Int’
      ‘x’ is a rigid type variable bound by
          a type expected by the context: [x] -> [x] at <interactive>:33:1
    Expected type: x -> x
      Actual type: Int -> Int
    In the first argument of ‘map’, namely ‘addOne’
    In the first argument of ‘example2’, namely ‘(map addOne)’

......但不是这样的:

lens

就实际效用而言,rank-n类型广泛用于(例如)Functor库。这允许您表达函数使用Functor实例而不知道它是哪个特定fmap实例(即,它只使用Functor)的想法。因此,当你传递它时,你可以给它任何你想要的 $allowed_extensions = array("gif", "jpeg", "jpg", "png"); $files = glob('files/*'); natcasesort($files); foreach($files as $file){ if(!in_array(end(explode(".",$file)),$allowed_extensions)){ $image = "http://fitter.henry-griffitts.com/fitter/images/pdf.png"; }else{ $image = $file; } echo '<div class="one_half"><img src="' . $image . '" class="images" /></br><h2>' .basename($file). '</h2><a class="download" href="http://fitter.henry-griffitts.com/fitter/download.php?file='.base64_encode($file).'"></a></div>'; } ?> 个实例。