Класс типа - это способ обобщения функций, чтобы они могли быть полиморфными, а другие могут реализовывать эти функции для своих типов. Возьмем в качестве примера класс типа Show
, который в упрощенной форме выглядит как
class Show a where
show :: a -> String
Это говорит о том, что любой тип, который реализует Show
класса типов могут быть преобразованы в String
(есть еще некоторые осложнения для более реалистичных ограничений, но точка Show
должна иметь возможность преобразовывать значения в String
с).
В этом случае функция show
имеет полный тип Show a => a -> String
.
Если мы рассмотрим функцию sqrt
, его тип
> :type sqrt
sqrt :: Floating a => a -> a
И abs
:
> :type abs
abs :: Num b => b -> b
Если вы спросите GHCI какие типы он будет использовать тип переменной a
в обоих случаях , но я использовал b
в сигнатуре типа для abs
, чтобы было ясно, что это разные переменные типа с тем же именем, и это поможет избежать путаницы на следующем шаге.
Эти сигнатуры типа означают, что sqrt
принимает значение, тип которого реализует Floating
класса типов (используйте :info Floating
для просмотра всех пользователей) и возвращает значение того же типа, и что функция abs
принимает значение, тип которого реализует Num
typeclass и возвращает значение того же типа.
Выражение abs(show)
эквивалентным образом анализируется как abs sqrt
, а это означает, что sqrt
это первый и единственный аргумент, передаваемый abs
. Однако мы просто сказали, что abs
принимает значение Num
, но sqrt
- это функция, а не число. Почему Хаскелл принимает это вместо того, чтобы жаловаться? Причину можно увидеть более четко, когда мы выполняем подстановку сигнатур типов. Так как sqrt
имеет тип Floating a => a -> a
, это должно совпадать с аргументом b
в подписи abs
, поэтому, заменив b
на Floating a => a -> a
, мы получим, что abs sqrt :: (Floating a, Num (a -> a)) => a -> a
.
Haskell фактически позволяет использовать тип функции для реализации класса Num
, вы можете сделать это самостоятельно, хотя это, вероятно, будет бессмысленным. Однако, просто потому, что что-то не имеет смысла для GHC, пока типы могут быть решены чисто, это позволит.
Вы не можете использовать эту функцию, она просто не имеет смысла. Нет встроенного экземпляра Num (a -> a)
для любого a
, поэтому вам нужно будет определить свой собственный. Вы можете, однако, составляют функции abs
и sqrt
используя оператор композиции .
:
> :type abs . sqrt
abs . sqrt :: Floating c => c -> c
И это имеет смысл. Эта функция эквивалентна
myfunc x = abs (sqrt x)
Здесь следует отметить, что x
сначала наносят sqrt
, а затем результат этого вычисления передается abs
, а не передавая функцию sqrt
в abs
.
Я голосую, чтобы закрыть этот вопрос как не по теме, потому что кажется, что вы никогда не потрудились проверить базовое введение в Haskell. Я честно удивляюсь, что заставило вас думать, что 'abs (sqrt)' будет работать и что заставило вас использовать такой синтаксис. –
@OtosakaYuu: это 'abs sqrt' не' abs (sqrt) '- последнее вводит в заблуждение как вы, так и некоторые другие люди; то есть о '((+1) (1))', который на самом деле jus t' ((+) 1) '(no parens вокруг' 1'), а секции операторов упрощают это до '(1 +)' even , Знание и соблюдение таких правил приведет к лучшему пониманию Haskell и чистого, идиоматического, профессионально выглядящего кода. –