我有一个虚构的列表,具有不同级别的嵌套,或者忽略了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?
答案 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]}
除娱乐目的外,不建议使用此解决方案。