Haskell中的类型条件控件

时间:2010-06-04 10:31:20

标签: haskell types typeclass

我正在通过99 Haskell problems来提高我对该语言的熟练程度。在问题7(“展平嵌套列表结构”)中,我发现自己想要根据传递给函数的参数类型定义条件行为。也就是说,因为

*Main> :t 1
1 :: (Num t) => t
*Main> :t [1,2]
[1,2] :: (Num t) => [t]
*Main> :t [[1],[2]]
[[1],[2]] :: (Num t) => [[t]]

(即嵌套在不同级别的列表具有不同的数据类型)似乎我应该能够编写一个可以读取参数类型的函数,然后相应地运行。我的第一次尝试就是这样:

listflatten l = do
    if (:t l) /= ((Num t) => [t]) then
        listflatten (foldl (++) [] l)
        else id l

但是当我尝试这样做时,Haskell会返回一个解析错误。 Haskell是否足够灵活以允许这种类型的操作,我是否需要找到另一种方式?

4 个答案:

答案 0 :(得分:11)

1。改为使用模式匹配

您可以在不动态检查数据类型的情况下解决该问题。事实上,在Haskell中很少需要它。通常你可以使用模式匹配。

例如,如果您有类型

data List a = Elem a | Nested [List a]

你可以模式匹配

flatten (Elem x) = ...
flatten (Nested xs) = ...
例:
data List a = Elem a | Nested [List a]
  deriving (Show)

nested = Nested [Elem 1, Nested [Elem 2, Elem 3, Nested [Elem 4]], Elem 5]
main = print $ flatten nested

flatten :: List a -> [a]
flatten (Elem x) = [x]
flatten (Nested lists) = concat . map flatten $ lists  

map flatten展平每个内部列表,因此它的行为类似于[List a] -> [[a]],我们在此处生成列表列表。 concat将所有列表合并在一起(concat [[1],[2,3],[4]]给出[1,2,3,4])。 concat . map flattenconcatMap flatten相同。

2。要动态检查类型,请使用Data.Typeable

如果在某些罕见的场合(不在此问题中)您确实需要动态检查类型,则可以使用Data.Typeable类型类及其typeOf函数。 :t仅适用于GHCI,它不是语言的一部分。

ghci> :m + Data.Typeable
ghci> typeOf 3 == typeOf "3"
False
ghci> typeOf "a" == typeOf "b"
True

可能,您也需要使用DeriveDataTypeable扩展程序。

答案 1 :(得分:6)

答案 2 :(得分:5)

您在解释器中使用内置函数混淆了交互式命令:t。您无法在运行时查询类型。

答案 3 :(得分:3)

查看该问题的示例:

flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])

如您所见,问题是您希望为任意嵌套列表创建自己的数据结构。

普通的haskell列表不能任意嵌套。列表中的每个元素都必须具有静态相同的类型,这就是动态检查元素类型没有意义的原因。

通常,haskell不允许您创建不同类型的列表,然后在运行时检查类型。您可以使用类型类来定义不同的行为,以便使用不同类型的参数进行展平,但这仍然不会为您提供任意嵌套的列表。