“扩展”Haskell中的列表列表

时间:2015-03-30 14:07:39

标签: list haskell

我有一个数据类型为SFeld的表(列表列表)。 SFeld是Int或Ints列表

data SFeld = E Int | M [Int]

type STable = [[SFeld]]

我想定义一个函数expandM :: STable -> [STable],它接受​​一个STable和#34;扩展"其中的每个M,以便为M列表中的每个值创建一个新的STable列表。听起来很混乱所以这是一个例子:

>> expandM [[E 1,M [1,2]],[M [2,3],E 2,E 4],[E 5]] = 

                 [ [[E 1,E 1],[E 2,E 2,E 4],[E 5]]
                 , [[E 1,E 2],[E 2,E 2,E 4],[E 5]]
                 , [[E 1,E 1],[E 3,E 2,E 4],[E 5]]
                 , [[E 1,E 2],[E 3,E 2,E 4],[E 5]]
                 ]

我如何实现这样的功能?

1 个答案:

答案 0 :(得分:3)

将列表中项目的所有可能组合放在一起是>>=实例的绑定运算符Monad []。专门为列表

的列表
(>>=) :: [a] -> (a -> [b]) -> [b]

对于列表中的每个项a,它运行函数a -> [b]以找出所有可能性,并在结果列表[b]中收集这些可能性。我们想要使用的基本功能与此签名相匹配;它从初始SFeld计算所有可能的SFeld

expandSFeld :: SFeld -> [SFeld]
expandSFeld (E x)  = [E x]
expandSFeld (M xs) = map E xs

SFeld被保存在现有结构中,STableSFeld列表。我们想在Monad []上使用STable实例的绑定,而不更改表的结构。通常,Traverable类描述了可以保留的结构,以便在结构内部运行的Monad 可以移动到结构的外部。

                                     -- v-------------v    flips Traverable from outside to inside      
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
     -- flips Monad from inside to outside ^-------^

Traversable还包含一个函数mapM,用于将函数a -> m b映射到t a,从而生成m (t b)。生成的t b具有与初始t a相同的结构。

mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
mapM k = sequence . fmap k

列表中有Traversable个实例。这意味着我们可以在列表中每个项目的某些Monad上执行操作时保留列表的结构。我们可以使用它来对行中的每个项执行expandSFeld操作,同时保留行的结构。

import Data.Traversable
import Prelude hiding (mapM)

expandSRow :: [SFeld] -> [[SFeld]]
expandSRow = mapM expandSFeld

我们可以对expandSRow中的每一行执行STable操作,同时保留STable的结构。

expandM :: STable -> [STable]
expandM = mapM expandSRow

生成的expandM函数会返回通过展开所有STable获得的每个M

expandM [[E 1,M [1,2]],[M [2,3],E 2]] 
[
  [[E 1,E 1],[E 2,E 2]],
  [[E 1,E 1],[E 3,E 2]],
  [[E 1,E 2],[E 2,E 2]],
  [[E 1,E 2],[E 3,E 2]]
]

Traverable类的功能可以更普遍地用于任何Applicative而不是任何Monad