Для начала у нас есть прекрасное определение
x = 1 : map (2*) x
что само по себе немного умопомрачительно, если вы никогда его раньше не видели. В любом случае это довольно стандартный трюк лени и рекурсии. Теперь мы избавимся от явной рекурсии с использованием fix
и без точки.
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
Мы можем избавиться от точек, заменить (.)
на (<$>)
, а затем добавить несколько ложных секций:
map = (=<<) . ((:[]) <$>)
map = (=<<) <$> ((:[]) <$>)
map = (<$> ((:[]) <$>)) (=<<)
Подставив это уравнение на наш предыдущий шаг:
x = fix (((<$>) <$> (:) <*> ((<$> ((:[]) <$>)) (=<<) <$> (*) <$> (*2))) 1)
Наконец, вы ломаете пробел и получаете чудесное окончательное уравнение
x=fix(((<$>)<$>(:)<*>((<$>((:[])<$>))(=<<)<$>(*)<$>(*2)))1)