数据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)
答案 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 Int
和falseFoo :: Foo Bool
,您实际上要求getFoo
返回其他类型,具体取决于您在运行时提供的值。你不能这样做。在Haskell中,所有类型都必须在编译时。
如果您想要做的只是将事物转换为字符串,为什么不首先将它存储为字符串?我猜的答案是,这实际上是你试图解决的真正问题的简化......(?)