После проигрывания вокруг с haskell немного я споткнулся эту функцию:
Prelude Data.Maclaurin> :t ((+) . ($) . (+))
((+) . ($) . (+)) :: (Num a) => a -> (a -> a) -> a -> a
(Данные. Maclaurin экспортируется векторным пространством пакета.), Таким образом, это берет Цифру, функцию, другую Цифру и в конечном счете возвращает Цифру. Что волшебство делает следующей работой?
Prelude Data.Maclaurin> ((+) . ($) . (+)) 1 2 3
6
2, очевидно, не функция (a-> a), или я пропускал что-то?
Модуль Data.NumInstances
того же пакета определяет экземпляр Num
для функции, возвращающие числа:
instance Num b => Num (a->b) where
(+) = liftA2 (+)
(*) = liftA2 (*)
fromInteger = pure . fromInteger
...
В Haskell целочисленный литерал, такой как 2
, является общим, поэтому он может представлять число для любого экземпляра Num
:
Prelude> :t 2
2 :: (Num t) => t
Чтобы преобразовать его в фактическое число типа, требуемого в конкретном контексте, вызывается fromInteger
из класса Num
.
Поскольку упомянутый выше вспомогательный модуль определяет экземпляр Num
для функций, 2
теперь можно преобразовать в функцию с помощью метода fromInteger
. там указано.
Итак, ghci вызывает fromInteger 2
, чтобы получить функцию, требуемую в качестве второго параметра конструкции в вопросе. Затем все выражение вычисляется как 6
.
У вас есть веская причина запутаться. Используя модуль Data.NumInstances
в GHC (который загружается из Data.Maclaurin
), можно привести Num
к постоянной функции.
Prelude Data.NumInstances> :t (2 :: (Num a) => a -> a)
(2 :: (Num a) => a -> a) :: (Num a) => a -> a
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 0
2
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 1000
2
Вычисление выражения, по существу,
((+) . ($) . (+)) 1 2 3 = ((+) . ($) . (1+)) 2 3
= ((+) (1+)) 2 3
-- (+) is defined for functions that return a Num
= ((+) (1+) (\_ -> 2)) 3
= ((+2) . (1+)) 3
= 6