[英]Simplifying Nested List input in Haskell
I'm making a function to flatten a nested list of arbitrary depth.我正在制作一个函数来展平任意深度的嵌套列表。
flatten.hs扁平化.hs
data NestedList a = Regular a | Nested [NestedList a]
flatten::NestedList a -> [a]
flatten (Regular a) = [a]
flatten (Nested a) = concatMap flatten a
Right now if I want to flatten the list [1,2,3,[1,[1, 2]],2]
I have to input it like (Nested [Regular 1, Regular 2, Regular 3, Nested [Regular 1, Nested [Regular 1, Regular 2]], Regular 2])
.现在,如果我想展平列表
[1,2,3,[1,[1, 2]],2]
我必须像(Nested [Regular 1, Regular 2, Regular 3, Nested [Regular 1, Nested [Regular 1, Regular 2]], Regular 2])
。 Is there a way to simplify the input value?有没有办法简化输入值? I know about
OverloadedLists
but have no idea how to work with them.我知道
OverloadedLists
但不知道如何使用它们。
You can get part-way there with OverloadedLists
:您可以通过
OverloadedLists
获得部分OverloadedLists
:
The key here is defining an IsList
instance.这里的关键是定义一个
IsList
实例。 With overloaded lists, if GHC sees something like:对于重载列表,如果 GHC 看到如下内容:
[x,y,z]
and can parse x
, y
, z
as all the same type item
, then it will put them into a list [x,y,z] :: [item]
and call:并且可以将
x
, y
, z
解析为所有相同类型的item
,然后将它们放入列表[x,y,z] :: [item]
并调用:
fromList :: [item] -> NestedList a
You have to choose the right definition of item
to get this to work.您必须选择正确的
item
定义才能使其发挥作用。 And, since you want to be able to write:而且,由于您希望能够编写:
[[another_nested_list],[another_nested_list]]
with the inner lists parsed exactly the same way, it turns out you need item
to be NestedList a
, too:内部列表以完全相同的方式解析,结果你也需要
item
是NestedList a
:
fromList :: [NestedList a] -> NestedList a
This gives the IsList
instance:这给出了
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
With this in place, you can write:有了这个,你可以写:
> flatten [Regular 1, Regular 2, Regular 3, [Regular 1, [Regular 1, Regular 2]], Regular 2]
[1,2,3,1,1,2,2]
Unfortunately, it doesn't work without the Regular
s because 1
can't be parsed as an item
, namely NestedList a
.不幸的是,它在没有
Regular
s 的情况下不起作用,因为1
不能被解析为item
,即NestedList a
。
You can play a dirty trick by defining a Num
instance to parse the integer literal into a NestedList a
like so:您可以通过定义一个
Num
实例来将整数文字解析为NestedList a
来玩一个肮脏的把戏,如下所示:
instance (Num a) => Num (NestedList a) where
fromInteger = Regular . fromInteger
and that'll let you write:这会让你写:
flatten [1,2,3,[1,[1,2]],2]
> [1,2,3,1,1,2,2]
That gets it working with integers only.这使它仅适用于整数。 If you try to write:
如果您尝试编写:
> flatten [[1.5,2.5]]
> flatten [["bar"],[["foo"]]
you'll get errors.你会得到错误。 You'd need to define a
Fractional
instance to handle 1.5
and an IsString
instance (using OverloadedStrings
) to handle "bar"
.您需要定义一个
Fractional
实例来处理1.5
和一个IsString
实例(使用OverloadedStrings
)来处理"bar"
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.