Ответ 1
Так как в первом выражении первый 199
имеет тип Integer
, а второй имеет Int
. Но во втором выражении оба типа Int
и factorial 199
не могут быть представлены типом Int
.
Используя следующие определения:
lenDigits n = length (show n)
factorial n = product [1..n]
Я оцениваю следующие
Prelude> ((lenDigits . factorial) 199) <= 199
False
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199
True
В чем причина такого поведения? Как я вижу, первое выражение совпадает с вторым выражением с уменьшенным lambdas.
Так как в первом выражении первый 199
имеет тип Integer
, а второй имеет Int
. Но во втором выражении оба типа Int
и factorial 199
не могут быть представлены типом Int
.
Здесь идет пошаговое рассмотрение этого вопроса.
Начнем с:
((lenDigits . factorial) 199) <= 199
В соответствии с Haskell Report...
Integer литерал представляет приложение функции
fromInteger
к соответствующему значению типаInteger
.
Это означает, что на самом деле наше первое выражение:
((lenDigits . factorial) (fromInteger (199 :: Integer))
<= (fromInteger (199 :: Integer))
Сам по себе fromInteger (199 :: Integer)
имеет полиморфный тип Num a => a
. Теперь нам нужно выяснить, является ли этот тип специализированным в контексте всего выражения. Заметим, что пока мы не найдем причину, по которой это не так, мы должны предположить, что полиморфные типы двух вхождений fromInteger (199 :: Integer)
независимы (Num a => a
и Num b => b
, если вы это сделаете).
lenDigits
- Show a => a -> Int
, и поэтому...
(lenDigits . factorial) (fromInteger (199 :: Integer))
... слева от <=
должен быть Int
. Учитывая, что (<=)
Ord a => a -> a -> Bool
, fromInteger (199 :: Integer)
справа от <=
также должен быть Int
. Тогда все выражение будет выглядеть следующим образом:
((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)
В то время как второй 199
был специализирован на Int
, первый из них по-прежнему является полиморфным. В отсутствие аннотаций другого типа дефолт делает его специализированным на Integer
, когда мы используем выражение в GHCi. Поэтому мы в конечном итоге получаем:
((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)
Теперь, во второе выражение:
(\i -> ((lenDigits . factorial) i) <= i) 199
По тем же рассуждениям, которые использовались выше, (lenDigits . factorial) i
(слева от <=
) есть Int
, и поэтому i
(справа от <=
) также является Int
. Таким образом, у нас есть...
GHCi> :t \i -> (lenDigits . factorial) i <= i
\i -> (lenDigits . factorial) i <= i :: Int -> Bool
... и поэтому применение его к 199
(которое фактически fromInteger (199 :: Integer)
) специализируется на int, давая:
((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)
Первый 199
теперь Int
, а не Integer
. factorial (199 :: Int)
переполняет тип фиксированного размера Int
, что приводит к фиктивному результату. Один из способов избежать этого - ввести явный fromInteger
, чтобы получить что-то, эквивалентное первому сценарию:
GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199
False