Вопрос

I have to derive the type of this function:

func x = map -1 x

And I've already found a way, using a tip to change it to a lambda expression:

func = \x -> (map) - (1 x)

If I express it like that, its fine and I get the same type as the original, but I'm not sure why its grouped like this. Could someone explain it?

For example, why isn't it like this:

func = \x -> (map - 1) x

or something similar.

I know it's a useless function etc. but I can't change the function, I just have to derive its type.

If you write this function in a file, eg: test.hs has func x = map -1 x and use :t func in the interpreter, it will reply:

func :: (Num (t -> (a -> b) -> [a] -> [b]),
         Num ((a -> b) -> [a] -> [b])) =>
         t -> (a -> b) -> [a] -> [b]
Это было полезно?

Решение

I now believe you meant to ask why

func x = map -1 x

has the type (Num (t -> (a -> b) -> [a] -> [b]), Num ((a -> b) -> [a] -> [b])) => t -> (a -> b) -> [a] -> [b], and how you can bracket the expression to make it have that type.

First, you have to recognise that the space is an operator in haskell, and has the highest precedence of all.

Let's use # instead of space, with highest precedence we can:

infixl 9 #
f # x = f x

We can replace and space without an operator with #:

func x = map - 1 # x

because the space between 1 and x was the only one without an operator (- is between map and 1).

Since # has higher precedence than -, we get

func x = map - (1 # x)

or equivalently

func x = map - (1 x)

Another example

func2 x = map (-1) x
> :t func2
func2 :: Num (a -> b) => [a] -> [b]

This translates as

func2' x = map # (-1) # x

but why isn't there a # between the - and the 1? In this case, - in front of a numeric literal like 1 means 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

So this function is trying to map the negative of 1 over a list. For that to work, it would need negative 1 to be a function, which is why it needs a numeric instance for functions (the Num (a->b) => at the start of the type).

Другие советы

but i'm not sure why its grouped like this. Could someone explain it? In example, why its not like that:

   func = \x -> (map - 1) x

Precedence. The language definition specifies that the precedence of (prefix) function application is higher than that of any infix operator, so

map -1 x

is parsed as the application of the infix operator (-) to the two operands map and 1 x, like 3 + 4 * 5 is parsed 3 + (4 * 5) due to the higher precedence of (*) compared to that of (+).

Although the interpreter has assigned a type to the expression, it's not a sensible one. Let's see what the function should be

func x = map -1 x

looks like we want to bracket that like this

func x = map (-1) x

in the hope that it subtracts one from each element of a list, but unfortunately, the - is considered to be negation when it's in front of a numeric literal, so we need to bracket it to change it into the subtraction function:

func x = map ((-) 1) x

Now this function subtracts each number in the list from 1:

 func [1,2,3]
=[(-) 1 1,  (-) 1 2,   (-) 1 3]
=[  1-1,      1-2,        1-3]
=[   0,       -1,         -2]

The type is

func :: Num a => [a] -> [a]

If you wanted to subtract one from each element of the list, rather than subtracting each element of the list from 1, you could use func x = map (subtract 1) x. As hammar points out, the subtract function exists exactly for the purpose of allowing this.


Your alternative

func = \x -> (map - 1) x

This can't work because (-) has type Num a => a -> a -> a, whereas map has type (a -> b) -> [a] -> [b]. You can't subtract one from a function, because a function isn't a numeric value.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top