函数返回 GADT 的任何构造函数的结果
Function returning result of any constructor of a GADT
当我尝试创建函数 returning Thing a
(其中 Thing
是 GADT)时,我目前正在与类型检查器发生冲突。一个最小的人为示例:
{-#LANGUAGE GADTs, EmptyDataDecls #-}
module Main where
-- Define a contrived GADT
data TFoo
data TBar
data Thing a where
Foo :: Int -> Thing TFoo
Bar :: String -> Thing TBar
combine :: [Thing a]
combine = [Foo 1, Bar "abc"]
main :: IO ()
main = undefined
类型检查器对 a
与 TBar
不匹配感到不满。大概这是因为它已经推断出a
是TFoo
。但是,这令人惊讶,因为使用常规求和类型你可以做到:
data Thing = Foo Int | Bar String
combine :: [Thing]
combine = [Foo 1, Bar "abc"]
有没有 return GADT 参数的类型参数?
在人为示例的上下文之外,我需要 GADT,这样我就可以键入某些函数以仅采用 Foo
,但在此之前我还需要能够 return Thing
列表。
你搞错了量词。
combine :: [Thing a]
表示(forall
隐含在语法中)
combine :: forall a. [Thing a]
本质上,无论 a
是什么,combine
都必须是 [Thing a]
,因为 a
是由调用 combine
的代码选择的。或者,从另一个意义上说,
-- psuedo-Haskell
combine :: (a :: *) -> [Thing a]
combine
是一个将类型作为参数并承诺构造该类型的 Things
列表的函数。具有这种类型签名的 combine
唯一可能的定义是 combine = []
,加上一堆像 [undefined]
等愚蠢的定义。 combine = [Foo 1]
也不起作用,因为没有推断出 a
,因为设置 a
的不是 combine
;是用户。
你想要
-- psuedo-Haskell
combine :: [exists a. Thing a]
意思是“combine
是一个事物列表,每个事物都是某种未知类型的 Thing
”(每个 Thing
都可以是不同的类型)。 exists
量词是 forall
的反面。这意味着 combine
的定义可以设置它想要的任何类型,用户将不得不处理它。 Haskell不支持exists
out-of-the-box,所以需要定义一个中间数据类型:
data SomeThing = forall a. SomeThing (Thing a)
使用通用量词创建存在量词的语法有点倒退,但想法是你得到
SomeThing :: forall a. Thing a -> SomeThing
这基本上消除了 a
是什么的知识。
然后你可以
combine :: [SomeThing]
combine = [SomeThing $ Foo 1, SomeThing $ Bar "abc"]
当我尝试创建函数 returning Thing a
(其中 Thing
是 GADT)时,我目前正在与类型检查器发生冲突。一个最小的人为示例:
{-#LANGUAGE GADTs, EmptyDataDecls #-}
module Main where
-- Define a contrived GADT
data TFoo
data TBar
data Thing a where
Foo :: Int -> Thing TFoo
Bar :: String -> Thing TBar
combine :: [Thing a]
combine = [Foo 1, Bar "abc"]
main :: IO ()
main = undefined
类型检查器对 a
与 TBar
不匹配感到不满。大概这是因为它已经推断出a
是TFoo
。但是,这令人惊讶,因为使用常规求和类型你可以做到:
data Thing = Foo Int | Bar String
combine :: [Thing]
combine = [Foo 1, Bar "abc"]
有没有 return GADT 参数的类型参数?
在人为示例的上下文之外,我需要 GADT,这样我就可以键入某些函数以仅采用 Foo
,但在此之前我还需要能够 return Thing
列表。
你搞错了量词。
combine :: [Thing a]
表示(forall
隐含在语法中)
combine :: forall a. [Thing a]
本质上,无论 a
是什么,combine
都必须是 [Thing a]
,因为 a
是由调用 combine
的代码选择的。或者,从另一个意义上说,
-- psuedo-Haskell
combine :: (a :: *) -> [Thing a]
combine
是一个将类型作为参数并承诺构造该类型的 Things
列表的函数。具有这种类型签名的 combine
唯一可能的定义是 combine = []
,加上一堆像 [undefined]
等愚蠢的定义。 combine = [Foo 1]
也不起作用,因为没有推断出 a
,因为设置 a
的不是 combine
;是用户。
你想要
-- psuedo-Haskell
combine :: [exists a. Thing a]
意思是“combine
是一个事物列表,每个事物都是某种未知类型的 Thing
”(每个 Thing
都可以是不同的类型)。 exists
量词是 forall
的反面。这意味着 combine
的定义可以设置它想要的任何类型,用户将不得不处理它。 Haskell不支持exists
out-of-the-box,所以需要定义一个中间数据类型:
data SomeThing = forall a. SomeThing (Thing a)
使用通用量词创建存在量词的语法有点倒退,但想法是你得到
SomeThing :: forall a. Thing a -> SomeThing
这基本上消除了 a
是什么的知识。
然后你可以
combine :: [SomeThing]
combine = [SomeThing $ Foo 1, SomeThing $ Bar "abc"]