多态数据类型的函数
Functions to Polymorphic data types
数据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
属于 class Show
所以我可以像这样使用 getFoo
:
main = getLine >>= (print . getFoo)
也许您想从 Foo 中省略类型参数。
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'
getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo
如果 fiveFoo :: Foo Int
和 falseFoo :: Foo Bool
,您实际上是在要求 getFoo
到 return 不同的类型,具体取决于您在 [=22= 处输入的值]-时间。你不能那样做。在 Haskell 中,所有类型必须在 编译时 时已知。
如果您只想将其转换为字符串,为什么不首先将其存储为字符串呢?我猜答案是这实际上是对您要解决的实际问题的简化...(?)
您可以使用existential types隐藏数据类型,"carry"像Show
这样的类型class。
请注意,像这样使用存在类型被认为是 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
数据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
属于 class Show
所以我可以像这样使用 getFoo
:
main = getLine >>= (print . getFoo)
也许您想从 Foo 中省略类型参数。
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'
getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo
如果 fiveFoo :: Foo Int
和 falseFoo :: Foo Bool
,您实际上是在要求 getFoo
到 return 不同的类型,具体取决于您在 [=22= 处输入的值]-时间。你不能那样做。在 Haskell 中,所有类型必须在 编译时 时已知。
如果您只想将其转换为字符串,为什么不首先将其存储为字符串呢?我猜答案是这实际上是对您要解决的实际问题的简化...(?)
您可以使用existential types隐藏数据类型,"carry"像Show
这样的类型class。
请注意,像这样使用存在类型被认为是 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