2016-10-01 2 views
-1
foo :: a -> b -> c 
foo = undefined 

ghci> :t foo 
foo :: a -> b -> c 

ghci> :t foo . foo 
foo . foo :: a -> b -> c 

ghci> :t foo . foo . foo 
foo . foo . foo :: a -> b -> c 

И так далее."foo" - "a -> b -> c". «foo. foo» также «a -> b -> c». Haskell относится к ним точно так же с точки зрения скорости?

Типы те же. Мы также ясно видим, просто взглянув на типы, что все три эквивалентны. Они имеют одинаковый результат.

А как насчет скорости? Например, будет foo составлен для себя миллион раз с . автоматически (без оптимизации) бегать так же быстро, как foo? Если нет, будет ли оптимизация (O1 или O2) сделать это так?

+3

Вы конкретно спрашиваете о 'a -> b -> c', где мы можем видеть по типу, что единственный возможный результат - это не прерывание? – sepp2k

+3

Любое количество foo, сложенных вместе, будет работать почти мгновенно и терпеть неудачу. Возможно, переосмыслите свой вопрос? Как насчет 'succ. succ'? –

ответ

3

Да, они выполняют то же самое, но только случайно. В GHCI:

> :i . 
(.) :: (b -> c) -> (a -> b) -> (a -> c)  -- Defined in ‘GHC.Base’ 
infixr 9 . 

Поскольку infixr, foo . foo . foo разбирает, как foo . (foo . foo), и поэтому мы можем писать ярлык foo . foo . foo . ... миллиард раз foldr. Итак:

> let foo :: a -> b -> c; foo = undefined 
> foldr (.) id (replicate 1000000000 foo)() 
*** Exception: Prelude.undefined 
CallStack (from HasCallStack): 
    error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err 
    undefined, called at <interactive>:1:5 in interactive:Ghci1 

Он возвращается почти сразу. С другой стороны, следующие два повисеть:

> foldl (.) id (replicate 1000000000 foo)() 
> foldr (flip (.)) id (replicate 1000000000 foo)() 

Однако, я должен еще раз подчеркнуть, что это совпадение реализации GHC, а не гарантия сделала семантику языка. Так получилось, что реализация GHC imprecise exceptions быстро замечает, что это будет ошибка (и выбрасывает самую левую ошибку foo) в случае foldr (.), но не так быстро отмечает foldl (.). И, конечно же, в случае, когда foo является не просто ошибкой, но и должен выполнять некоторые фактические вычисления, что вычисление нужно будет выполнять столько раз, сколько оно появляется в строке композиций - GHC довольно удивительно, но не волшебный ,

+0

Хотя этот вид производительности не гарантируется семантикой языка, реализация должна быть довольно странной, чтобы дать совершенно разные результаты. В частности, строгая спецификация 'foldr', не относящаяся к позвоночнику, практически требует лени, но строгая спецификация' foldl', не связанная с аккумулятором, фактически требует энтузиазма позвоночника. – dfeuer

+0

@dfeuer Действительно, но даже в этом случае это просто случайность: я считаю, что это быстро, потому что оно бросает исключение. Разумеется, любой реальный код должен запускать все итерации 'foo'. –

+0

постоянная функция также будет быстрой с 'foldr', но не' foldl'. И я думаю, вы могли бы построить несколько менее тривиальные примеры. – dfeuer

Смежные вопросы