首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >存在类型包装器必然性

存在类型包装器必然性
EN

Stack Overflow用户
提问于 2012-06-03 21:56:10
回答 3查看 375关注 0票数 5

事实证明,尽管它们背后的想法非常简单,但正确使用存在/排名-n类型是令人惊讶的困难。

为什么有必要将存在类型包装到data类型中?

我有一个简单的例子:

代码语言:javascript
复制
{-# LANGUAGE RankNTypes, ImpredicativeTypes, ExistentialQuantification #-}
module Main where

c :: Double
c = 3

-- Moving `forall` clause from here to the front of the type tuple does not help,
-- error is the same
lists :: [(Int, forall a. Show a => Int -> a)]
lists = [ (1, \x -> x)
        , (2, \x -> show x)
        , (3, \x -> c^x)
        ]

data HRF = forall a. Show a => HRF (Int -> a)

lists' :: [(Int, HRF)]
lists' = [ (1, HRF $ \x -> x)
         , (2, HRF $ \x -> show x)
         , (3, HRF $ \x -> c^x)
         ]

如果我注释掉lists的定义,代码将成功编译。如果我不注释掉它,我会得到以下错误:

代码语言:javascript
复制
test.hs:8:21:
    Could not deduce (a ~ Int)
    from the context (Show a)
      bound by a type expected by the context: Show a => Int -> a
      at test.hs:8:11-22
      `a' is a rigid type variable bound by
          a type expected by the context: Show a => Int -> a at test.hs:8:11
    In the expression: x
    In the expression: \ x -> x
    In the expression: (1, \ x -> x)

test.hs:9:21:
    Could not deduce (a ~ [Char])
    from the context (Show a)
      bound by a type expected by the context: Show a => Int -> a
      at test.hs:9:11-27
      `a' is a rigid type variable bound by
          a type expected by the context: Show a => Int -> a at test.hs:9:11
    In the return type of a call of `show'
    In the expression: show x
    In the expression: \ x -> show x

test.hs:10:21:
    Could not deduce (a ~ Double)
    from the context (Show a)
      bound by a type expected by the context: Show a => Int -> a
      at test.hs:10:11-24
      `a' is a rigid type variable bound by
          a type expected by the context: Show a => Int -> a at test.hs:10:11
    In the first argument of `(^)', namely `c'
    In the expression: c ^ x
    In the expression: \ x -> c ^ x
Failed, modules loaded: none.

为什么会发生这种情况?第二个例子不应该等同于第一个吗?这些n级类型的用法有什么不同?当我需要这样的多态性时,有没有可能省去额外的ADT定义,只使用简单的类型?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-06-03 22:06:41

关于存在类型的处理,您必须考虑两个问题:

如果存储"anything that can be shown“,则必须存储可显示的内容,以及如何显示实际变量只能有一种类型。

第一点是为什么你必须有存在类型包装器,因为当你写这个的时候:

代码语言:javascript
复制
data Showable = Show a => Showable a

实际发生的情况是像这样的东西被声明:

代码语言:javascript
复制
data Showable a = Showable (instance of Show a) a

即,与值a一起存储对Show a的类实例的引用。如果不这样做,您就不能拥有一个解开Showable的函数,因为该函数不知道如何显示a

第二点是为什么你有时会遇到一些类型怪异,以及为什么你不能在let绑定中绑定存在类型。

你在代码中的推理也有问题。如果你有一个像forall a . Show a => (Int -> a)这样的函数,你会得到一个给定任意整数的函数,它将能够产生调用者选择的任何类型的可显示值。您可能指的是exists a . Show a => (Int -> a),这意味着如果函数获得一个整数,它将返回某个存在Show实例的类型。

票数 3
EN

Stack Overflow用户

发布于 2012-06-03 22:12:13

您的第一次尝试不是使用存在类型。而是你的

代码语言:javascript
复制
lists :: [(Int, forall a. Show a => Int -> a)]

要求第二个组件可以提供我选择的任何可显示类型的元素,而不仅仅是您选择的某种可显示类型。你要找的是

代码语言:javascript
复制
lists :: [(Int, exists a. Show a * (Int -> a))]  -- not real Haskell

但你不是这么说的。数据类型打包方法允许您通过刷新从forall恢复exists。你有

代码语言:javascript
复制
HRF :: forall a. Show a => (Int -> a) -> HRF

这意味着要构建HRF值,必须提供一个包含类型a的三元组、一个用于aShow字典和一个Int -> a中的函数。也就是说,HRF构造函数的类型有效地限制了这个非类型

代码语言:javascript
复制
HRF :: (exists a. Show a * (Int -> a)) -> HRF   -- not real Haskell

您可以通过使用rank类型来对存在词进行教会编码,从而避免使用datatype方法

代码语言:javascript
复制
type HRF = forall x. (forall a. Show a => (Int -> a) -> x) -> x

但这可能有点过头了。

票数 6
EN

Stack Overflow用户

发布于 2012-06-03 22:06:32

这些例子是不等价的。第一,

代码语言:javascript
复制
lists :: [(Int, forall a. Show a => Int -> a)]

表示每个第二个组件都可以生成任何所需的类型,只要它是来自IntShow实例。

第二个示例是对类型包装进行取模,该类型包装等同于

代码语言:javascript
复制
lists :: [(Int, exists a. Show a => Int -> a)]

也就是说,每个第二个组件都可以从Int中产生属于Show的某种类型,但您不知道该函数返回哪种类型。

此外,放入元组中的函数不满足第一个约定:

代码语言:javascript
复制
lists = [ (1, \x -> x)
        , (2, \x -> show x)
        , (3, \x -> c^x)
        ]

\x -> x生成的类型与作为输入给出的结果的类型相同,所以这里的类型是Intshow总是生成一个String,所以它是一个固定的类型。最后,\x -> c^x生成与c相同的类型,即Double

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10870945

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档