类型的约束多态

3

我试图定义一组受限制的多态值,例如:

myList = ["foo", 5] :: [Show a => a]

执行以下代码时会出现错误(GHCi, version 8.6.5)

GHC目前不支持陈述多态

无论如何,有没有可能指定一种类型,使得像f :: Show a => [a] -> [String]这样的函数可以消耗上述限制值?

换句话说,有没有一种方法可以通过编译器验证以下代码?

(++ "fork") . show <$> ["foo", 5]

我目前正在尝试通过定义一个值和期望结果的数据集[(value, "expectedResult")]来测试GADT类型类实例中的Show。但是,由于GADT构造函数指定了值的类型,因此不能简单地这样做。


一个列表包含相同类型的元素。请注意,这不起作用,因为String->StringshowInt->Stringshow不同。那么在<$>左侧的show的类型将是什么? - Willem Van Onsem
1
类型将会是 forall a. Show a => [a] -> [String],我希望通过使用 RankNTypes,可能有可能实现它。 - Nicolas Heimann
3
你可以使用存在类型包装器,但这会导致 [Wrapper],这是一个复杂的类型,与简单的 [String] 是同构的。这是一个已知的反模式。 - chi
1个回答

6
[Show a => a]并不是你认为的意思。它是[∀ a . Show a => a] 的速记,即一系列值每个都是多态的,而不是包含具体(但未知)类型的多态列表。那将是存在值[∃ a . Show a => a]
虽然Haskell没有匿名存在值的类型表达式,但可以通过声明类型来获得它们。
{-# LANGUAGE GADTs #-}

data Showable where
  Showable :: Show a => a -> Showable

myList :: [Showable]
myList = [Showable "foo", Showable 5]

Main*> map (\(Showable x) -> show x ++ "fork") myList 
["\"foo\"fork","5fork"]

然而,正如chi已经评论的那样,做这件事是没有意义的:你可以可能做的全部都是展示一个Show约束的存在类型,也就是说,它的所有信息都可以被捕捉到一个字符串中。好了,那么直接存储这个字符串吧!

myList :: [String]
myList = [show "foo", show 5]

2
这甚至对于Show来说也不是100%正确的,因为showsPrec具有稍微更多的信息。但无论如何,即使对于多方法类,您始终可以将所有方法简单地存储为部分应用函数。 - leftaroundabout
1
实际上它是 forall a. [Show a => a] -- 它是一个同质列表,其中包含您喜欢的任何类型a的每个元素都需要a的显示实例。这种类型的唯一值是[],因此Show部分完全不必要。另一方面,[Read a => a]有点有趣。 - luqui
1
@leftaroundabout,我认为这通常比存在包装器更好。到目前为止,我只发现很少的情况下无法删除存在包装器,例如class C a where { s :: a->a ; z :: a->Bool } - 在这里我们无法轻松地预先应用该值。我们可以将exists a. C a转换为几乎同构的[Bool],但这可能不太方便使用。 - chi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接