Haskell:如何构建异构类型

Haskell:如何构建异构类型,haskell,types,Haskell,Types,我想建立一个类型,以匹配任何东西,但从来没有被使用 例如: type Any = forall a. a f :: (x, Any) -> (Any, y) -> (x,y) f (x,_) (_,y) = (x,y) 这在{-#LANGUAGE impindicativetypes}中编译得很好,但是如果我尝试 f ("hi", 2) (3, (1, 2)) 我得到一个错误: <interactive>:19:9: No instance for (Num

我想建立一个类型,以匹配任何东西,但从来没有被使用

例如:

type Any = forall a. a
f :: (x, Any) -> (Any, y) -> (x,y)
f (x,_) (_,y) = (x,y)
这在
{-#LANGUAGE impindicativetypes}
中编译得很好,但是如果我尝试

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))
:19:9:
没有由文字“2”产生的(Num a)实例
可能的解决方案:
将(Num a)添加到上下文所需类型的上下文中:a
在表达式中:2
在“f”的第一个参数中,即“hi”,2”
在表达式中:f(“hi”,2)(3,(1,2))
:19:13:
没有由文字'3'产生的(Num a)实例
可能的解决方案:
将(Num a)添加到上下文所需类型的上下文中:a
在表达式中:3
在'f'的第二个参数中,即`(3,(1,2))'
在表达式中:f(“hi”,2)(3,(1,2))

如果我只希望x和y是Num,那就好了,但是我计划用这个做什么,需要比那个灵活得多。我对所有a都了解。a匹配所有类型,但只能传递一个永远无法计算的thunk和bottom。但是,我不想研究任何类型的列表。

从评论中可以看出,真正的问题是:如何键入使用字面语法编写的列表
[“a”,False]

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

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

{-# LANGUAGE GADTs #-}
data Box where
    Box :: a -> Box
然后列表
[Box“a”,Box False]
将在类型
[Box]
处正确键入。但是,如果您愿意对每个元素应用一个函数,那么您最好跳过所有类型的把戏,改为执行以下操作:

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

然后
[toast“a”,toast False]
有一个非常容易理解的类型
[()]

我认为对
任何类型都有一个基本的误解。让我通过几个例子来解释

“任意生产者”函数

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

“任何消费者”函数

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

您试图传递的是
2
,它不是任何类型的,只是任何数字类型的。因此出现了类型错误

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

type Any = exists a. a  -- INVALID Haskell
f :: Any -> ...
但遗憾的是,哈斯克尔不允许这种存在类型。如果需要该类型,则必须将其装箱:

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

caller = f (Any 'd')
或者,您可以将
exists
提升到顶层。由于它处于负数位置,因此对于所有

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

它不能工作,因为您的
Any
实际上是
All
。它只能由具有每种类型的表达式构造(类似于
未定义的

您需要使用
{-#LANGUAGE存在主义量化#-}来构建一个真正的
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)]

为什么你不能用另一个类型变量,比如
z
而不是
Any
?这会变得非常脆弱,我不知道如果你永远不能用它来做任何特定的事情,为什么你想要一个存在的Any类型<代码>数据。动态
是处理运行时之前未知类型的首选方法。您不能传递
2
,因为它属于所有a的
类型。Num a=>a
不是类型
Any
。您唯一可以传递的是
未定义的
和类似的底部。我认为您需要在问题中添加这些关于您计划如何使用您的类型的详细信息,也许还需要指出您将如何生成将由您的函数过滤的数据。@BT。您实际上为什么要这样做?如果你给你的问题提供更多的背景,你也许会得到一些好的建议。啊,我忘了制片人。这将彻底破坏类型安全性。悲哀,让我想做的事情复杂化了。但是,谢谢你的回答。这相当酷。
data Any = forall a . Any a
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)]