我有两个函数,仅当C是特定模式时才执行某些操作。 每个函数输出一个C列表。
我的目标是,给定[C],我想获得在列表中调用f1和f2的所有可能性,而其余部分保持不变。例如:
假设C的列表为:
c1
c2 --matches the pattern
c3
然后我想要一个包含两个列表的列表
[[c1] ++ (f1 c2) ++ [c3],[c1] ++ (f2 c2) ++ [c3]]
但是,如果我有
c1
c2 --matches the pattern
c3 --matches the pattern
然后我们应该有4个列表,因为我们希望调用f1和f2的所有组合。 这样就可以了:
[(f1 c1) ++ (f1 c2) ++ [c3], (f2 c1) ++ (f2 c2) ++ [c3],
(f1 c1) ++ (f2 c2) ++ [c3], (f2 c1) ++ (f1 c2) ++ [c3]]
目前,我的代码大致采用以下方式构建:
f1 :: C -> [C]
f2 :: C -> [C]
combine :: [C] -> [[C]]
combine my_pattern:xs = ?
combine (x:xs) = ?
combine [] = []
where first_set = (f1 my_pattern)
second_set = (f2 my_pattern)
有人可以对我如何填补其余部分给出直觉吗? Data.List中是否有任何有用的功能?我查看了文档,但无法立即注意到哪个文档可能会有所帮助。
答案 0 :(得分:2)
其他答案对我来说似乎很复杂。在这个答案中,我将进一步评论:这只是一个foldMap
,结合了不确定性monad(列表!)和序列monoid(列表!)。
首先编写适用于列表中单个元素的内容:
singleElement x
| matchesThePattern x = [f1 x, f2 x]
| otherwise = [[x]]
然后将其应用于每个元素:
import Data.Monoid
combine = foldMap (Ap . singleElement)
就是这样。这就是整个代码。
例如,假设我们想将每个字母重复2或3次,即x
-> xx
或xxx
,而所有其他字符都保持相同。
singleElement x
| 'a' <= x && x <= 'z' = [[x, x], [x, x, x]]
| otherwise = [[x]]
然后我们可以在ghci中尝试它:
> combine "123def"
Ap {getAp = ["123ddeeff","123ddeefff","123ddeeeff","123ddeeefff","123dddeeff","123dddeefff","123dddeeeff","123dddeeefff"]}
当然,在您自己的代码中选择比singleElement
更好的名称。
答案 1 :(得分:1)
我的方法是
x
或my_pattern
)。这意味着生成一个或多个新列表。xs
)的问题。这将给您返回列表列表([[C]]
)。[C]
)中的每个列表都将与步骤2中列表([C]
)中的每个列表([[C]]
)合并。 我有两种可能的方法。
我不清楚您正在寻找多少帮助,因此我的回答有些“没有破坏者”。如果需要,请进行澄清或更多详细信息。
无需深入研究Applicative
或Traversable
类型类的杂草,就可以通过列表理解来完成所需的工作。
让我们考虑一下您的模式是否匹配的情况。我会写一个列表理解如下:
[ x ++ y | x <- _, y <- _] :: [[C]]
-- this means
-- x :: [C]
-- y :: [C]
-- _ :: [[C]]
此列表理解可创建列表列表。 x
是前置的,因此它应该来自功能f1
和f2
的应用。 y
是每个结果列表的结尾。我会让你知道这可能是什么。
不匹配的情况比这简单,可以这样写
[ x : y | y <- _] :: [[C]]
-- note that x is not local to the list comprehension
-- y :: [C]
-- _ :: [[C]]
尽管这实际上只是上述列表理解的一个特例。
解决此问题的另一种方法是使用Applicative
的{{1}}实例。
让我们检查列表[a]
实例下的函数(<*>)
。
Applicative
此函数具有一种奇怪的类型签名。它需要一个功能列表和一个列表,然后返回另一个列表。具有将每个功能-- this is the type when specialized to lists
(<*>) :: [a -> b] -> [a] -> [b]
依次应用于a -> b
的每个元素的作用。
[a]
我们想退出>>> [(+1), (+2)] <*> [1,2,3]
-- [2,3,4] comes from (+1)
-- [3,4,5] comes from (+2)
[2,3,4,3,4,5]
,而不是[[C]]
,因此,如果我们想使用[C]
,我们可以将其类型更专门化
(<*>)
为避免混淆,我建议选择(<*>) :: [a -> [C]] -> [a] -> [[C]]
,这样可以
a = [C]
您的函数列表应该在要生成的列表上添加正确的元素。第二个参数应该是递归调用返回的列表。
答案 2 :(得分:1)
您必须拥有
applicable_f1 :: C -> Bool
applicable_f2 :: C -> Bool
以某种方式定义。然后,
combinations :: [C] -> [[C]]
combinations cs = map concat . sequence $
[ concat $ [ [ [c] | not (applicable_f1 c || applicable_f2 c)]
, [ f1 c | applicable_f1 c]
, [ f2 c | applicable_f2 c] ]
| c <- cs]