多态数据类型的函数

hom*_*mam 4 polymorphism haskell existential-type gadt

数据Foo a定义如下:

data Foo a where
  Foo :: (Typeable a, Show a) => a -> Foo a
  -- perhaps more constructors

instance Show a => Show (Foo a) where
  show (Foo a) = show a
Run Code Online (Sandbox Code Playgroud)

有些情况:

fiveFoo :: Foo Int
fiveFoo = Foo 5

falseFoo :: Foo Bool
falseFoo = Foo False
Run Code Online (Sandbox Code Playgroud)

我如何定义任何函数b -> Foo a,例如:

getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo
Run Code Online (Sandbox Code Playgroud)

这里getFoo没有打字检查Couldn't match type ‘a’ with ‘Bool’.

我唯一感兴趣的是a上课,Show所以我可以使用getFoo:

main = getLine >>= (print . getFoo)
Run Code Online (Sandbox Code Playgroud)

Pi *_*ort 5

您可以使用存在类型使数据类型隐藏并"携带"类似于Show周围的类型类.

请注意,使用这样的存在类型被认为是Haskell中的反模式,您可能需要仔细考虑是否真的要这样做:更明确地了解类型通常更简单,更好,并且更不容易出错.

但是,话虽这么说,如果你真的想这样做,下面是你如何在你的例子中使用存在类型:

{-# LANGUAGE ExistentialQuantification #-}

-- This Foo can only be constructed with instances of Show as its argument.
data Foo = forall a. Show a => Foo a

-- Note that there is no "Show a => ..." context here:
-- Foo itself already carries that constraint around with it.
instance Show Foo where
  show (Foo a) = show a


getFoo :: String -> Foo
getFoo "five" = Foo 5
getFoo "false" = Foo False

main = print . getFoo =<< getLine
Run Code Online (Sandbox Code Playgroud)

示范:

ghci> main
five
5
ghci> main
false
False
Run Code Online (Sandbox Code Playgroud)

  • `data Foo a` ---`a`在这里是多余的,`forall`里面的"内部"`a`是一个不同的变量! (3认同)
  • 此外,GADT解决方案几乎与存在解决方案完全相同(我之所以仅使用GADT,因为OP使用了一个)GADT是否包含存在类型? (2认同)