Haskell : 如何构建异构类型 Any
Haskell : How to build the Heterogeneous Type Any
我想构建一个类型来匹配任何东西,但永远不会被使用。
示例:
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。但是,我不想研究 Any 类型。
从评论来看,真正的问题似乎是:如何键入用文字语法 ["a", False]
编写的列表?
答案(幸运的是!)是 "you can't"。
你可以创建一个存在类型,并用存在类型包装每个元素。如果你想这样做,你可以这样做:
{-# LANGUAGE GADTs #-}
data Box where
Box :: a -> Box
然后列表 [Box "a", Box False]
将在类型 [Box]
上正确键入。但是,如果您愿意对每个元素应用一个函数,那么您不妨跳过所有的类型恶作剧并改为执行以下操作:
toss :: a -> ()
toss _ = ()
然后[toss "a", toss False]
有非常好理解的类型[()]
。
我认为对 Any
类型存在根本性的误解。让我通过几个例子来解释。
一个"Any-producer"函数
f :: ... -> Any
可用于生成任何类型的值:它 return 是一个字符串,它同时也是一个整数、一对和一头大象。具体来说,它 return 底部(或者根本没有 return,如果你愿意的话)。
一个"Any-consumer"函数
f :: Any -> ...
期望被提供任何类型的值:调用者必须提供一个字符串,它也是一个整数和一个一对和一头大象同时出现。具体来说,调用者必须通过 bottom.
您正在尝试传递 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 -> ...)
这行不通,因为你的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)]
我想构建一个类型来匹配任何东西,但永远不会被使用。
示例:
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。但是,我不想研究 Any 类型。
从评论来看,真正的问题似乎是:如何键入用文字语法 ["a", False]
编写的列表?
答案(幸运的是!)是 "you can't"。
你可以创建一个存在类型,并用存在类型包装每个元素。如果你想这样做,你可以这样做:
{-# LANGUAGE GADTs #-}
data Box where
Box :: a -> Box
然后列表 [Box "a", Box False]
将在类型 [Box]
上正确键入。但是,如果您愿意对每个元素应用一个函数,那么您不妨跳过所有的类型恶作剧并改为执行以下操作:
toss :: a -> ()
toss _ = ()
然后[toss "a", toss False]
有非常好理解的类型[()]
。
我认为对 Any
类型存在根本性的误解。让我通过几个例子来解释。
一个"Any-producer"函数
f :: ... -> Any
可用于生成任何类型的值:它 return 是一个字符串,它同时也是一个整数、一对和一头大象。具体来说,它 return 底部(或者根本没有 return,如果你愿意的话)。
一个"Any-consumer"函数
f :: Any -> ...
期望被提供任何类型的值:调用者必须提供一个字符串,它也是一个整数和一个一对和一头大象同时出现。具体来说,调用者必须通过 bottom.
您正在尝试传递 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 -> ...)
这行不通,因为你的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)]