使用Haskell将随机嵌套列表展平为非嵌套列表

时间:2018-10-30 10:45:01

标签: parsing haskell abstract-syntax-tree

我有一个虚构的列表,具有不同级别的嵌套,或者忽略了API响应的丑陋类型,即:

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]

我要创建的函数应该执行以下操作:

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

我最初的想法是我必须将列表解析为AST(抽象语法树)-->,然后使用递归将所有分支平坦化,并将叶子分解为单个分支-->,然后将结果解析回去进入列表。

我不确定如何将列表解析为AST?还是有更好的解决方案?

edit-我想我太过直言了,因为代表[1, 2, [3, 4]]实际上是问题的一部分,因此,为了使事情更好地工作,从现实上讲,它们必须被表示为ADT / AST。因此,如果这是API响应或正在读取文件,我如何将这些数据解析为AST / ADT?

3 个答案:

答案 0 :(得分:3)

任意嵌套的列表不会输入check。列表的每个元素必须具有相同的类型,但是具有不同嵌套级别的列表具有不同的类型。解决此问题的技巧是将列表包装成新的数据类型,以隐藏嵌套级别的数量。但这只是一棵树。

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

然后,您可以实现flatten作为对树的遍历。

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

请参阅容器包装中的Data.Tree,以获取随时可用的版本。

对于解析,我建议使用aeson。 Data.Aeson.Types定义了实例FromJSON v => FromJSON (Tree v),因此您应该只能够在json字符串上使用decode并告诉它您想要一个Tree Int

decode rawJson :: Maybe (Tree Int)

答案 1 :(得分:3)

GHC已经为您完成了此操作。展平就是折叠。

> :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]

答案 2 :(得分:2)

不清楚您实际要实现的目标,但是实际上有一个语法黑客 允许您在Haskell中编写其他嵌套的列表语法并自动使其变平:

{-# 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]}

除娱乐目的外,不建议使用此解决方案。