Рассмотрите следующий очень простой пример использования монады массива и сделайте запись в качестве понимания списка или эквивалента для вложенного цикла:
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, а также концепцию преобразователей монад, потому что я думал, что каким-то образом монаду List / Array нужно объединить с монадой Writer, но я не смог найти решение.
Как бы высделать это?