考虑以下使用数组monad和do表示法作为列表理解或嵌套循环等效的非常简单的示例:
one :: String
one = joinWith "\n" $ do
n <- [ "1", "2" ]
x <- [ "a", "b" ]
y <- [ "A", "B" ]
pure $ n <> x <> y
-- this generates a string like:
1aA
1aB
1bA
1bB
2aA
2aB
2bA
2bB
现在想象一下,您宁愿在输出中包含一些标题和缩进,就像这样:
numbers
lowers
uppers
1aA
1aB
uppers
1bA
1bB
lowers
uppers
2aA
2aB
uppers
2bA
2bB
这是将产生上述字符串的修改:
two :: String
two = joinWith "\n" $ ["numbers"] <> do
n <- [ "1", "2" ]
pure $ joinWith "\n" $ [" lowers"] <> do
x <- [ "a", "b" ]
pure $ joinWith "\n" $ [" uppers"] <> do
y <- [ "A", "B" ]
pure $ " " <> n <> x <> y
这不再是那么漂亮和可读性了,如果事情变得比这个简化的示例复杂,那么最好有一种更好的表达方式。
以下伪代码可能会给出一个想法,我的想法是
three :: String
three = joinWith "\n" $ do
yield "numbers"
n <- [ "1", "2" ]
yield " lowers"
x <- [ "a", "b" ]
yield " uppers"
y <- [ "A", "B" ]
yield $ " " <> n <> x <> y
这似乎是更合理的DSL。我试图为此找到一个实现,但是没有成功。我研究了Writer monad以及monad转换器的概念,因为我认为在某种程度上必须将List / Array monad与writer monad结合起来,但是我找不到解决方案。
您将如何做?