多态数据类型的函数

时间:2016-08-25 10:54:51

标签: haskell polymorphism gadt existential-type

数据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

有些例子:

fiveFoo :: Foo Int
fiveFoo = Foo 5

falseFoo :: Foo Bool
falseFoo = Foo False

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

getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo

此处getFoo未使用Couldn't match type ‘a’ with ‘Bool’键入支票。

我唯一感兴趣的是a属于Show类,所以我可以像getFoo那样使用:

main = getLine >>= (print . getFoo)

3 个答案:

答案 0 :(得分:5)

您可以使用existential types隐藏数据类型并“携带”类似Show的类型类。

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

然而,话虽这么说,如果你真的想这样做,这里是你如何使用存在类型与你的例子:

{-# 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

演示:

ghci> main
five
5
ghci> main
false
False

答案 1 :(得分:4)

也许你想省略Foo中的type参数。

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

instance Show Foo where
  show (Foo a) = show a

fiveFoo :: Foo
fiveFoo = Foo (5 :: Int) -- (Foo 5) doesn't work because of ambiguity

falseFoo :: Foo
falseFoo = Foo False

getFoo :: String -> Foo
getFoo "five" = fiveFoo
getFoo "false" = falseFoo

print $ getFoo "five" -- prints '5'
print $ getFoo "false" -- prints 'False'

答案 2 :(得分:2)

getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo

如果fiveFoo :: Foo IntfalseFoo :: Foo Bool,您实际上要求getFoo返回其他类型,具体取决于您在运行时提供的值。你不能这样做。在Haskell中,所有类型都必须在编译时

中知道

如果您想要做的只是将事物转换为字符串,为什么不首先将它存储为字符串?我猜的答案是,这实际上是你试图解决的真正问题的简化......(?)