Ответ 1
Начнем с того, что у нас есть прекрасное определение
x = 1 : map (2*) x
который сам по себе немного умалчивает, если вы никогда его не видели. В любом случае это довольно стандартный трюк лени и рекурсии. Теперь мы избавимся от явной рекурсии с помощью fix
и point-free-ify.
x = fix (\vs -> 1 : map (2*) vs)
x = fix ((1:) . map (2*))
Следующее, что мы собираемся сделать, это развернуть раздел :
и сделать map
ненужным сложным.
x = fix ((:) 1 . (map . (*) . (*2)) 1)
Итак, теперь у нас есть две копии этой константы 1
. Это никогда не будет сделано, поэтому мы будем использовать приложение для чтения, чтобы его дублировать. Кроме того, состав функций немного мусор, поэтому замените его на (<$>)
, где бы мы ни находились.
x = fix (liftA2 (.) (:) (map . (*) . (*2)) 1)
x = fix (((.) <$> (:) <*> (map . (*) . (*2))) 1)
x = fix (((<$>) <$> (:) <*> (map <$> (*) <$> (*2))) 1)
Далее: этот вызов map
слишком читабельен. Но нечего бояться: мы можем использовать законы монады, чтобы немного расширить его. В частности, fmap f x = x >>= return . f
, поэтому
map f x = x >>= return . f
map f x = ((:[]) <$> f) =<< x
Мы можем с помощью point-free-ify заменить (.)
на (<$>)
, а затем добавить некоторые паразитные разделы:
map = (=<<) . ((:[]) <$>)
map = (=<<) <$> ((:[]) <$>)
map = (<$> ((:[]) <$>)) (=<<)
Подставляя это уравнение на предыдущем шаге:
x = fix (((<$>) <$> (:) <*> ((<$> ((:[]) <$>)) (=<<) <$> (*) <$> (*2))) 1)
Наконец, вы разбиваете свой пробел и получаете замечательное окончательное уравнение
x=fix(((<$>)<$>(:)<*>((<$>((:[])<$>))(=<<)<$>(*)<$>(*2)))1)