Рассмотрим этот код, который я использовал для решения проблемы Эйлера 58:
diagNums = go skips 2
where go (s:skips) x = let x' = x+s
in x':go skips (x'+1)
squareDiagDeltas = go diagNums
where go xs = let (h,r) = splitAt 4 xs
in h:go r
Мне не нравится сопоставление с образцом во второй функции. Это выглядит сложнее, чем нужно! Это то, что возникает довольно часто для меня. Здесь splitAt
возвращает кортеж, поэтому мне нужно сначала деструктурировать его, прежде чем я смогу выполнить рекурсию. Та же картина возникает, возможно, еще более раздражающе, когда моя рекурсия сама возвращает кортеж, который я хочу изменить. Рассмотреть возможность:
f n = go [1..n]
where go [] = (0,0)
go (x:xs) = let (y,z) = go xs
in (y+x, z-x)
по сравнению с красивой и простой рекурсией:
f n = go [1..n]
where go [] = 0
go (x:xs) = x+go xs
Конечно, функции здесь — полная ерунда, и их можно было бы написать совершенно по-другому и лучше. Но я хочу сказать, что потребность в сопоставлении с образцом возникает каждый раз, когда мне нужно передать более одного значения обратно через рекурсию.
Есть ли способы избежать этого, возможно, используя Applicative
или что-то подобное? Или вы считаете этот стиль идиоматичным?