Haskell, определяющий приоритет операторов над функциями
Я должен получить тип этой функции:
func x = map -1 x
И я уже нашел способ, используя подсказку, чтобы изменить его на лямбда-выражение:
func = \x -> (map) - (1 x)
Если я выражаю это так, это нормально, и я получаю тот же тип, что и оригинал, но я не уверен, почему это сгруппировано так. Может кто-нибудь объяснить это?
Например, почему это не так:
func = \x -> (map - 1) x
или что-то подобное.
Я знаю, что это бесполезная функция и т. Д., Но я не могу изменить функцию, мне просто нужно определить ее тип.
Если вы напишите эту функцию в файле, например: test.hs имеет func x = map -1 x
и использовать :t func
в переводчике он ответит:
func :: (Num (t -> (a -> b) -> [a] -> [b]),
Num ((a -> b) -> [a] -> [b])) =>
t -> (a -> b) -> [a] -> [b]
3 ответа
Теперь я верю, что вы хотели спросить, почему
func x = map -1 x
имеет тип (Num (t -> (a -> b) -> [a] -> [b]), Num ((a -> b) -> [a] -> [b])) => t -> (a -> b) -> [a] -> [b]
и как вы можете заключить в скобки выражение, чтобы оно имело этот тип.
Во-первых, вы должны признать, что пробел является оператором в haskell и имеет самый высокий приоритет среди всех.
Давайте использовать #
вместо пробела с наивысшим приоритетом мы можем:
infixl 9 #
f # x = f x
Мы можем заменить и пробел без оператора с #:
func x = map - 1 # x
потому что пространство между 1 и x было единственным без оператора (-
находится между map
а также 1
).
поскольку #
имеет более высокий приоритет, чем -
, мы получаем
func x = map - (1 # x)
или эквивалентно
func x = map - (1 x)
Другой пример
func2 x = map (-1) x
> :t func2
func2 :: Num (a -> b) => [a] -> [b]
Это переводится как
func2' x = map # (-1) # x
но почему нет # между -
и 1
? В этом случае, -
перед числовым буквенным как 1
средства negate
:
> (-1)
-1
> (negate 1)
-1
> (subtract 1)
<interactive>:73:1:
No instance for (Show (a0 -> a0))
arising from a use of `print'
Possible fix: add an instance declaration for (Show (a0 -> a0))
In a stmt of an interactive GHCi command: print it
Таким образом, эта функция пытается отобразить минус 1 по списку. Для того, чтобы это работало, ей понадобится отрицательный 1, чтобы быть функцией, поэтому ему нужен числовой экземпляр для функций (Num (a->b) =>
в начале типа).
но я не уверен, почему это сгруппировано так. Может кто-нибудь объяснить это? Например, почему это не так:
func = \x -> (map - 1) x
Внеочередные. Определение языка указывает, что приоритет приложения функции (префикса) выше, чем у любого инфиксного оператора, поэтому
map -1 x
анализируется как приложение инфиксного оператора (-)
на два операнда map
а также 1 x
, лайк 3 + 4 * 5
анализируется 3 + (4 * 5)
из-за более высокого приоритета (*)
по сравнению с (+)
,
Хотя интерпретатор назначил тип выражению, он не является разумным. Посмотрим, какой должна быть функция
func x = map -1 x
Похоже, мы хотим заключить в скобки, как это
func x = map (-1) x
в надежде, что он вычитает по одному из каждого элемента списка, но, к сожалению, -
считается отрицанием, когда он находится перед числовым литералом, поэтому нам нужно заключить его в скобки, чтобы преобразовать в функцию вычитания:
func x = map ((-) 1) x
Теперь эта функция вычитает каждое число в списке из 1:
func [1,2,3]
=[(-) 1 1, (-) 1 2, (-) 1 3]
=[ 1-1, 1-2, 1-3]
=[ 0, -1, -2]
Тип является
func :: Num a => [a] -> [a]
Если вы хотите вычесть по одному из каждого элемента списка, а не вычитать каждый элемент списка из 1, вы можете использовать func x = map (subtract 1) x
, Как указывает Хаммар, subtract
Функция существует именно с целью разрешения этого.
Ваша альтернатива
func = \x -> (map - 1) x
Это не может работать, потому что (-)
имеет тип Num a => a -> a -> a
, в то время как map
имеет тип (a -> b) -> [a] -> [b]
, Вы не можете вычесть одно из функции, потому что функция не является числовым значением.