Haskell:如何构建异构类型Any

时间:2015-01-10 19:52:52

标签: haskell types

我想构建一个类型,以匹配任何但从未使用过的类型。

示例:

type Any = forall a. a
f :: (x, Any) -> (Any, y) -> (x,y)
f (x,_) (_,y) = (x,y)

这可以用{-# LANGUAGE ImpredicativeTypes #-}进行编译,但如果我尝试

f ("hi", 2) (3, (1, 2))

我收到错误:

<interactive>:19:9:
    No instance for (Num a) arising from the literal `2'
    Possible fix:
      add (Num a) to the context of a type expected by the context: a
    In the expression: 2
    In the first argument of `f', namely `("hi", 2)'
    In the expression: f ("hi", 2) (3, (1, 2))

<interactive>:19:13:
    No instance for (Num a) arising from the literal `3'
    Possible fix:
      add (Num a) to the context of a type expected by the context: a
    In the expression: 3
    In the second argument of `f', namely `(3, (1, 2))'
    In the expression: f ("hi", 2) (3, (1, 2))

如果我只想让x和y成为Num,哪个会没问题,但我打算用这个做什么需要比那更灵活。我理解forall a. a匹配所有类型,但只能传递一个永远无法计算的thunk和bottom。但是,我不想看任何类型。

3 个答案:

答案 0 :(得分:6)

我认为对Any类型存在根本性的误解。让我通过几个例子来解释一下。

任何制片人&#34;功能

f :: ... -> Any

可用于生成任何类型的值:它返回一个字符串,该字符串也是一个整数,同时返回一对和一个大象。具体而言,如果您愿意,它会返回底部(或根本不返回)。

一个&#34;任何消费者&#34;功能

f :: Any -> ...

期望被赋予任何类型的值:调用者必须提供一个字符串,它同时也是一个整数,一对和一个大象。具体来说,调用者必须通过底部。

您正在尝试传递任何类型的2 - 它只有数字类型。因此类型错误。

如果你想写一个接受任何东西的函数,你应该写

type Any = exists a. a  -- INVALID Haskell
f :: Any -> ...
但是,唉,Haskell不允许这种存在类型。如果你想要那种类型,你必须把它装箱:

data Any = forall a . Any a
f :: Any -> ...

caller = f (Any 'd')

或者,您可以将exists提升到顶级。由于它处于负面位置,因此变为forall

f :: (exists a. a) -> ...
-- becomes
f :: forall a. (a -> ...)

答案 1 :(得分:5)

从评论中可以看出真正的问题是:如何输入用文字语法["a", False]编写的列表?

答案(幸运的是!)是“你不能”。

可以创建一个存在类型,并用存在主义包装每个元素。如果你想这样做,你可以这样做:

{-# LANGUAGE GADTs #-}
data Box where
    Box :: a -> Box

然后列表[Box "a", Box False]将在[Box]类型中输入。但是,如果你愿意为每个元素应用一个函数,那么你也可以跳过所有类型的恶作剧,并做这样的事情:

toss :: a -> ()
toss _ = ()

然后[toss "a", toss False]具有可理解的类型[()]

答案 2 :(得分:3)

它无效,因为您的Any实际上是All。它只能由具有各种类型的表达式构建(类似undefined)。

您需要使用{-# LANGUAGE ExistentialQuantification #-} to build a real Any`:

data Any = forall a . Any a

这需要是一种数据类型,因此您必须使用Any构造函数创建值,但现在您可以执行以下操作:

f :: [(x, Any)] -> [(Any, y)] -> [(x,y)]
f ((x, _) : xs) ((_, y) : ys) = (x,y) : f xs ys
f _ _ = []

> f [("hi", Any 'a'),("you", Any 3)] [(Any "a", 2),(Any Nothing, 4)]
[("hi",2),("you",4)]