我正在制作一个函数来展平任意深度的嵌套列表。
flatten.hs
data NestedList a = Regular a | Nested [NestedList a]
flatten::NestedList a -> [a]
flatten (Regular a) = [a]
flatten (Nested a) = concatMap flatten a
现在,如果我想拼合列表[1,2,3,[1,[1, 2]],2]
,则必须像(Nested [Regular 1, Regular 2, Regular 3, Nested [Regular 1, Nested [Regular 1, Regular 2]], Regular 2])
一样输入。有没有一种方法可以简化输入值?我了解OverloadedLists
,但不知道如何使用它们。
答案 0 :(得分:3)
您可以通过OverloadedLists
到达那里:
此处的关键是定义一个IsList
实例。对于超载列表,如果GHC看到类似以下内容:
[x,y,z]
并可以将x
,y
,z
解析为所有相同的类型item
,然后将它们放入列表[x,y,z] :: [item]
中并调用:
fromList :: [item] -> NestedList a
您必须选择正确的item
定义才能使它起作用。并且,由于您希望能够编写:
[[another_nested_list],[another_nested_list]]
内部列表的解析方式完全相同,事实证明您也需要item
成为NestedList a
:
fromList :: [NestedList a] -> NestedList a
这给出了IsList
实例:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedLists #-}
import GHC.Exts
data NestedList a = Regular a | Nested [NestedList a] deriving (Show)
instance IsList (NestedList a) where
type Item (NestedList a) = NestedList a
fromList = Nested
在此位置,您可以编写:
> flatten [Regular 1, Regular 2, Regular 3, [Regular 1, [Regular 1, Regular 2]], Regular 2]
[1,2,3,1,1,2,2]
不幸的是,如果没有Regular
,它就无法工作,因为1
不能被解析为item
,即NestedList a
。
您可以通过定义Num
实例来将整数文字解析为NestedList a
来耍个肮脏的招,就像这样:
instance (Num a) => Num (NestedList a) where
fromInteger = Regular . fromInteger
那会让你写:
flatten [1,2,3,[1,[1,2]],2]
> [1,2,3,1,1,2,2]
这使它仅适用于整数。如果您尝试写:
> flatten [[1.5,2.5]]
> flatten [["bar"],[["foo"]]
您会得到错误。您需要定义一个Fractional
实例来处理1.5
和一个IsString
实例(使用OverloadedStrings
)来处理"bar"
。