简体   繁体   English

简化 Haskell 中的嵌套列表输入

[英]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:内部列表以完全相同的方式解析,结果你也需要itemNestedList 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM