Приложение с частичной функцией Haskell с $

Я новичок в Haskell и смотрю на простой пример использования приложения функции с $,

Это кажется простым - он берет функцию и применяет ее к значению.

Так что это имеет смысл:

> (+3) $ 2
5

Это также имеет смысл:

> ($) (+3) 2
5

Это имеет смысл, потому что первый аргумент является функцией, а второй аргумент является значением.

Теперь об использовании $ создать частичную функцию.

Глядя на типы, это имеет смысл - просто нужно Num введите значение для b:

> :t ($) (+3)
($) (+3) :: Num b => b -> b

Но вот где я заблудился - что здесь происходит?

> :t ($) (2)
($) (2) :: Num (a -> b) => a -> b

Я ожидал, что первый аргумент должен быть функцией, а не простым значением Num.

Итак, вот мои вопросы:

  1. Что тут происходит?
  2. Что значит ограничение Num (a -> b) синтаксис значит?
  3. Какой пример использования ($) таким образом, это начинается с чего-то вроде ($) (2)?

Спасибо!

1 ответ

Решение

С одной стороны, числовые литералы, такие как 2 на самом деле читаются как fromInteger 2 :: Num a => a поэтому может обозначать любое значение типа Num a => a имеется ввиду любой тип, который находится в классе типов Num то есть имеет среди прочего специальную версию fromInteger определенный, который возвращает фактическое значение фактического типа, преобразованное из целого числа 2:

> :i Num
class Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a

Как сказано в руководстве по Haskell (в 10.3),

Целое число (без десятичной точки) фактически эквивалентно применению fromInteger к значению числа в виде Integer,

С другой стороны, ($) имеет тип

> :t ($)
($) :: (a -> b) -> a -> b

Итак, мы имеем

fromInteger 2 :: Num a1 =>   a1
($)           ::          (a -> b) -> a -> b
--------------------------------------------
($) 2         :: Num      (a -> b) => a -> b

Так что это функция, которая также должна быть в классе типов Num,

Обычно это не так, но Haskell не знает, можно ли импортировать какой-то модуль, который определяет такой экземпляр:

instance Num (a -> b) where
   ....
   fromInteger n = ....
   ....

поэтому он допускает такую ​​возможность при проверке типа, и только тогда, видя, что такой фактический экземпляр нигде не определен, он ошибается.

Например, следуя подсказке augustss в комментариях,

instance (Num b) => Num (a -> b) where
   (+) f g x = f x + g x
   (*) f g x = f x * g x
   abs f x = abs (f x)
   negate f x = negate (f x)
   signum f x = signum (f x)
   fromInteger n = const (fromInteger n)

давайте напишем (sin + 2 * cos^2) x,

Другие вопросы по тегам