Функция Haskell для длины списка
чтобы рассчитать длину списка, используя foldr, можно было бы сделать что-то вроде:
foldr (_ acc -> acc + 1) 0
расширяя далее идею о том, что функция складывания должна увеличивать второй аргумент, я придумал это (и это неправильно):
foldr ((+1) . (flip const)) 0`
дальнейший осмотр типа показывает это:
(+1) . (flip const) :: Num (c -> c) => a -> c -> c
функция высшего порядка Haskell для вычисления длины На этой странице есть интересный комментарий, который я не могу понять действительно
foldr (((+1).).(flip const)) 0
может кто-нибудь объяснить, как эта композиция на самом деле работает ?
2 ответов
прежде всего, давайте сосредоточимся почему foldr ((+1) . (flip const)) 0
- это неправильно. Вы хотите увеличить только второй аргумент и забыть первую. Семантически это
\_ a -> a + 1
однако вы написали следующее:
(+1) . flip const
= (+1) . (\_ a -> a)
= \x -> (+1) . (\_ a -> a) $ x
= \x -> (+1) $ (\_ a -> a) $ x
= \x -> (+1) $ \a -> a
= \_ -> (+1) (\a -> a)
= const ( (+1) (\a -> a))
именно поэтому вам внезапно нужно Num (c -> c)
, так как вы пытаетесь применить (+1)
on id
.
но вы на самом деле имели в виду:
\_ a -> a + 1
= \_ a -> (+1) a
= \_ -> (+1)
= const (+1)
в конце концов, вы хотите забыть первый аргумент и использовать функцию f
на второй. Все, что вам нужно, это использовать const f
.
состав ((+1).).(flip const)
слишком многословен и, вероятно, генерируется pointfree:
((+1).).(flip const)
= ((\x -> x + 1).) . (\a _ -> a)
= \c -> ((\x -> x + 1).) . (\a _ -> a) $ c
= \c -> ((\x -> x + 1).) $ \_ -> c
= \c -> \f -> (\x -> x + 1) . f $ \_ -> c
= \c -> (\x -> x + 1) . \_ -> c
= \_ c -> (\x -> x + 1) $ c
= \_ c -> c + 1
это действительно комментарий, но слишком длинный для одного.
если вы не имеете дело со странными числами, такими как lazy Nat
s, вы действительно хотите
length xs = foldl' (\acc _ -> 1 + acc) 0 xs
делает это бессмысленным,
length = foldl' (\acc -> const ((1+) acc)) 0
length = foldl' (const . (1+)) 0
если хотите, вы можете преобразовать оригинал foldl'
на foldr
форма Вот так:
length xs = foldr go id xs 0 where
go _ r acc = r $! 1 + acc
жуя go
,
go _ r acc = ($!) r $ (+) 1 acc
go _ r = ($!) r . (+1)
go _ r = (. (+1)) (($!) r)
go _ = (. (+1)) . ($!)
go = const ((. (+1)) . ($!))
жуя length
,
length = flip (foldr go id) 0
собираем все вместе,
length = flip (foldr (const ((. (+1)) . ($!))) id) 0
Я, например, нахожу эту свободную от точки форму совершенно непрозрачной.