Ответ 1
Мое намерение состоит в том, чтобы дополнить ehird ответ немного более подробным объяснением. Когда вы написали выражение
3 4
Затем интерпретатор Haskell считает, что вы пытаетесь применить функцию 3
к любому 4
. Для того, чтобы Haskell интерпретировал 3
как функцию, ему необходимо сделать вызов функции
fromInteger :: Integer -> (a -> b)
чтобы получить функцию (т.е. что-то типа a -> b
) из целого числа 3
. Теперь fromInteger
определяется в Num
typeclass, чтобы иметь подпись
instance Num x where
fromInteger :: Integer -> x
то есть. когда вы делаете тип x
экземпляром класса Num
, вы предоставляете реализацию fromInteger
, которая сообщает Haskell, как преобразовать целочисленный литерал в x
. В вашем случае x
- это тип функции a -> b
. Так что сделай это!
Во-первых, некоторые шаблоны. Чтобы сделать x
экземпляр Num
, Haskell требует, чтобы мы также сделали его экземпляром Show
и Eq
:
instance Show (a -> b) where show f = "<function>"
instance Eq (a -> b) where f == g = False
Теперь скажем, что мы хотим интерпретировать 3 4
как "4 по модулю 3". Затем нам нужно сообщить Haskell, как интерпретировать любое целое число как функцию, которая вызывает mod
. Более того, поскольку mod
принимает только интегральные типы (имеет подпись mod :: Integral a => a -> a -> a
), то нам нужно также ограничить типы a
и b
:
instance (Integral a, Integral b) => Num (a -> b) where
Чтобы создать экземпляр Num
, нам нужно предоставить реализации (+)
, (-)
, (*)
и fromIntegral
(на самом деле мы должны также определить пару других функций, но не будем беспокоиться об этом сейчас).
Существует довольно естественный способ определения сложения, вычитания и умножения (весь код здесь является частью экземпляра Num
и должен иметь отступ по отношению к объявлению экземпляра)
f + g = \x -> f x + g x
f - g = \x -> f x - g x
f * g = \x -> f x * g x
то есть. когда вы добавляете две функции f
и g
, вы получаете новую функцию, которая применяет как f
, так и g
к ее аргументу, а затем добавляет их вместе. Поскольку нам потребовалось, чтобы результат применения f
и g
был интегрального типа, мы знаем, что имеет смысл добавить свои выходы.
Чтобы интерпретировать целое число как функцию, мы можем написать
fromInteger n = \m -> fromIntegral m `mod` fromIntegral n
то есть. когда у нас есть целое число n
, мы возвращаем функцию параметра m
, которая при вызове гарантирует, что оба аргумента одного типа (путем вызова fromIntegral
на обоих из них), а затем использует их как аргументы к функции mod
.
Наконец, немного больше шаблонов, чтобы остановить Haskell, жалуясь:
abs f = undefined
signum f = undefined
Мы можем проверить это. У меня есть код в файле numfun.hs. Я загружаю интерпретатор Haskell и загружаю файл:
Prelude> :l numfun.hs
[1 of 1] Compiling Main ( numfun.hs, interpreted )
Ok, modules loaded: Main.
Теперь я могу определить некоторые функции:
*Main> let f = (+ 1)
*Main> let g = (* 2)
Я могу добавить их или вычесть из них:
*Main> (f + g) 3 -- (3+1) + (3*2)
10
*Main> (f - g) 3 -- (3+1) - (3*2)
-2
И я могу вызывать числа как функции:
*Main> 3 4 -- 4 `mod` 3
1