Flatten randomly nested list into a non nested list using Haskell

时光总嘲笑我的痴心妄想 提交于 2019-12-11 08:30:30

问题


I have an imaginary list with different levels of nesting, or ignoring the ugly types a API response ie:

a ::(Num a, Num [a], Num [[a]]) => [[a]]
a = [1, 2, [3, 4]]

b :: (Num a, Num [a], Num [[a]], Num [[[a]]]) => [[[[a]]]]
b = [[1,2,[3]],4]

The function I'm trying to create should do the following:

myFunc a == [1,2,3,4]
myFunc b == [1,2,3,4]

My initial thought was I'd have to parse the list into an AST (Abstract syntax tree) --> use recursion to flatten all the branches & leaves into a single branch --> parse the result back into a list.

I'm unsure how to parse the list into AST? or is there a better solution?

edit -- I think I was trying to be too literal, in that representing [1, 2, [3, 4]] is actually part of the problem, so realistically for things to work better they would need to be represented as an ADT/AST. So if this was an API response or reading a file how would I parse that data into it's AST/ADT?


回答1:


An arbitrarily nested list won't type check. Each element of a list has to have the same type, but lists with different nesting levels have different types. The trick to get around this is to wrap a list into a new data type that hides the number of nested levels. But this is just a tree.

data Tree a = Root a | Branches [Tree a]

Then you can implement flatten as a traversal of the tree.

flatten :: Tree a -> [a]
flatten (Root a)          = [a]
flatten (Branches (t:ts)) = flatten t ++ (concat (fmap flatten ts))

See Data.Tree in the containers package for a ready-to-use version.

For parsing, I would recommend using aeson. Data.Aeson.Types defines the instance FromJSON v => FromJSON (Tree v), so you should just be able to use decode on the json string and tell it you want a Tree Int.

decode rawJson :: Maybe (Tree Int)



回答2:


This is already done for you by the GHC. Flattening is folding.

> :set -XDeriveFoldable

> data NList a = A a | N [NList a] deriving (Show, Functor, Foldable)
data NList a = A a | N [NList a]

> foldMap pure (N[ A 1, N[ A 2], A 3]) :: [Int]
[1,2,3]

> foldMap pure (N[ N[ N[ N[ A 1]]], N[ A 2], A 3]) :: [Int]
[1,2,3]



回答3:


Unclear what you're actually trying to achieve, but there is a syntax hack that actually allows you to write differently-nested list syntax in Haskell and have it flattened automatically:

{-# LANGUAGE TypeFamilies #-}

import GHC.Exts (IsList(..))

newtype AutoflatList a = AutoflatList {getFlatList :: [a]}
   deriving (Show)

instance IsList (AutoflatList a) where
  type Item (AutoflatList a) = AutoflatList a
  fromList segs = AutoflatList $ getFlatList =<< segs
  toList = pure

instance Num a => Num (AutoflatList a) where
  fromInteger = AutoflatList . pure . fromInteger
*Main> :set -XOverloadedLists
*Main> [1, 2, [3, 4]] :: AutoflatList Int
AutoflatList {getFlatList = [1,2,3,4]}
*Main> [[1,2,[3]],4] :: AutoflatList Int
AutoflatList {getFlatList = [1,2,3,4]}

This solution not recommended except for recreational purposes.



来源:https://stackoverflow.com/questions/53062580/flatten-randomly-nested-list-into-a-non-nested-list-using-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!