Haskell:如何构建异构类型Any

BT.*_*BT. 3 haskell types

我想建立一个类型,以匹配任何东西,但永远不会被使用.

例:

type Any = forall a. a
f :: (x, Any) -> (Any, y) -> (x,y)
f (x,_) (_,y) = (x,y)
Run Code Online (Sandbox Code Playgroud)

{-# LANGUAGE ImpredicativeTypes #-}如果我尝试,这编译得很好

f ("hi", 2) (3, (1, 2))
Run Code Online (Sandbox Code Playgroud)

我收到错误:

<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))
Run Code Online (Sandbox Code Playgroud)

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

chi*_*chi 6

我认为这种Any类型存在根本性的误解.让我通过几个例子来解释.

"任何生产者"功能

f :: ... -> Any
Run Code Online (Sandbox Code Playgroud)

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

"任意消费者"功能

f :: Any -> ...
Run Code Online (Sandbox Code Playgroud)

期望得到任何类型的值:调用者必须提供一个字符串,它也是一个整数,一对和一个大象同时.具体地说,呼叫者必须通过底部.

您正在尝试传递2,这不是任何类型 - 它只是任何数字类型.因此类型错误.

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

type Any = exists a. a  -- INVALID Haskell
f :: Any -> ...
Run Code Online (Sandbox Code Playgroud)

但是,唉,Haskell不允许这种存在类型.如果你想要那种类型,你必须把它装箱:

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

caller = f (Any 'd')
Run Code Online (Sandbox Code Playgroud)

或者,您可以将其提升exists到顶层.由于它处于负面位置,它变成了一个forall

f :: (exists a. a) -> ...
-- becomes
f :: forall a. (a -> ...)
Run Code Online (Sandbox Code Playgroud)


Dan*_*ner 5

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

答案(幸运的是!)是"你不能".

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

{-# LANGUAGE GADTs #-}
data Box where
    Box :: a -> Box
Run Code Online (Sandbox Code Playgroud)

然后列表[Box "a", Box False]将在类型上输入[Box].但是,如果您愿意将函数应用于每个元素,那么您也可以跳过所有类型的恶作剧,并执行以下操作:

toss :: a -> ()
toss _ = ()
Run Code Online (Sandbox Code Playgroud)

然后[toss "a", toss False]是非常容易理解的类型[()].