
The function g, when called with a binary function returns a type error which I’d really like to understand: why is this type “infinite" rather than just incomplete or something similar? I would have expected some kind of partial binding. Can someone help me with an explanation? Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> f sum <interactive>:14:3: Occurs check: cannot construct the infinite type: a ~ a -> a Expected type: (a -> a) -> a -> a Actual type: a -> a -> a Relevant bindings include it :: (a -> a) -> a -> a (bound at <interactive>:14:1) In the first argument of ‘f’, namely ‘sum’ In the expression: f sum With a similar call using lambda expressions, the error is different: Prelude> (\x y -> x + y) . (\x y -> x + y) <interactive>:32:1: Non type-variable argument in the constraint: Num (a -> a) (Use FlexibleContexts to permit this) When checking that ‘it’ has the inferred type it :: forall a. (Num a, Num (a -> a)) => a -> (a -> a) -> a -> a Prelude>

I'm curious as to the intended meaning of let f g = g . g Without reading further down, I immediately thought: "composing g onto g must require that the argument and result types (domain and range) of g must be identical". Then, when I read f sum I don't know what that means, given that sum is [1] "a function of two arguments" yielding a single value (or, if I want to have my daily dose of curry, sum is [2] "a function of one argument yielding a (function of one argument yielding a single value)". With either reading, I don't know how to reconcile sum with the expectation on the argument to f. I think that's what the compiler is saying as well. Expected type: (a -> a) -> a -> a Actual type: a -> a -> a The "expected type" expression seems to match what I expected from the definition of f, and the "actual type" expression seems to match reading [2]. So I'm wondering how that aligns with what you intended to express. -jn- On Sun, Jan 3, 2016 at 7:31 AM, Julian Rohrhuber < julian.rohrhuber@musikundmedien.net> wrote:
The function g, when called with a binary function returns a type error which I’d really like to understand: why is this type “infinite" rather than just incomplete or something similar? I would have expected some kind of partial binding. Can someone help me with an explanation?
Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> f sum
<interactive>:14:3: Occurs check: cannot construct the infinite type: a ~ a -> a Expected type: (a -> a) -> a -> a Actual type: a -> a -> a Relevant bindings include it :: (a -> a) -> a -> a (bound at <interactive>:14:1) In the first argument of ‘f’, namely ‘sum’ In the expression: f sum
With a similar call using lambda expressions, the error is different:
Prelude> (\x y -> x + y) . (\x y -> x + y)
<interactive>:32:1: Non type-variable argument in the constraint: Num (a -> a) (Use FlexibleContexts to permit this) When checking that ‘it’ has the inferred type it :: forall a. (Num a, Num (a -> a)) => a -> (a -> a) -> a -> a Prelude>
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
-- Beauty of style and harmony and grace and good rhythm depend on simplicity. - Plato

Hello Julian, Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> f sum If you are trying to call 'f' and see the result, args are missing. If you are trying to create new type, use 'let'. Prelude> (\x y -> x + y) . (\x y -> x + y) Similar story. Let or args ;)

Hi all, than you for your helpful replies.
On 03.01.2016, at 16:03, Imants Cekusins
wrote: Hello Julian,
Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> f sum
If you are trying to call 'f' and see the result, args are missing.
If you are trying to create new type, use 'let'.
Prelude> (\x y -> x + y) . (\x y -> x + y)
Similar story. Let or args
Hello Imants – same with “let” here: Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> let sum' = f sum <interactive>:43:14: Occurs check: cannot construct the infinite type: a ~ a -> a
On 03.01.2016, at 14:42, Joel Neely
wrote: I'm curious as to the intended meaning of let f g = g . g
Without reading further down, I immediately thought: "composing g onto g must require that the argument and result types (domain and range) of g must be identical”.
yes, that domain and range are the same is implied when you rise a function "to a power” (which is what f does). I just assumed that arity and type are two different things in Haskell.
Then, when I read
f sum
I don't know what that means, given that sum is [1] "a function of two arguments" yielding a single value (or, if I want to have my daily dose of curry, sum is [2] "a function of one argument yielding a (function of one argument yielding a single value)".
With either reading, I don't know how to reconcile sum with the expectation on the argument to f.
As you wondered what I was trying to express, I was thinking along reading [2]. With: Prelude> let z = sum 2 Prelude> let z' = f z z' is a function with one argument, and yes, this works because z was one with a single argument. But assuming that function composition (.) is a function too, I was curious what would happen if I applied it partially. So an intermediate step would have been this: let k = (\x y -> x + y) . (\x -> x + 1) which is fine. It leaves a binary op function as I expected. By contrast, let k = (\x y -> x + y) . (\x y -> x + y) returns Non type-variable argument in the constraint: Num (a -> a) Instead of something like following which I had dared to expect: let k = (\z -> (\x y -> x + y + z)) What really made me wonder then was how come that f sum would return not a "Non type-variable argument”, but "cannot construct the infinite type: a ~ a -> a” Where does the infinity come from?

Prelude> let f g = g . g Prelude> let sum x y = x + y Prelude> let sum' = f sum Occurs check: cannot construct the infinite type: a ~ a -> a If f and sum were defined in a module, given a signature, I suppose this would compile. Similarly, sometimes valid functions defined within function body without signatures sometimes make compiler complain. Once such functions are moved to top (module) level and given a signature, compiler is happy.

Where does the infinity come from?
Here is composition signature: (.) http://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#v:. :: (b -> c) -> (a -> b) -> a -> c It looks like it is applicable to functions with 1 arg. Sum expects 2 args. I guess this explains why sum can not be passed to f

On Sun, Jan 3, 2016 at 1:05 PM, Imants Cekusins
Here is composition signature:
(.) http://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#v:. :: (b -> c) -> (a -> b) -> a -> c
It looks like it is applicable to functions with 1 arg. Sum expects 2 args. I guess this explains why sum can not be passed to f
This isn't accurate, and it's useful to understand why. Every function in Haskell has exactly one argument. Joel touched on this earlier. It's easier to see if you add the implied parentheses to the type signatures: sum :: Num a => a -> (a -> a) f :: (a -> a) -> (a -> a) To really drive it home, let's play with synonyms. type Endo' a = (a -> a) Endo already exists as a newtype in Data.Monoid, thus Endo' here. Now: sum :: Num a => a -> Endo' a f :: Endo' a -> Endo' a

Well even if (.) can be used with functions returning functions (partially applied), calling g . g where g expects 2 args and returns 1 does not seem intuitive. Could you think of a useful practical example of (a->a->a) . (a->a->a) ?

Every function in Haskell has exactly one argument.
well partially applied functions may be used in the intermediary stages of function processing however if programmer expects a function to return primitive value (as opposed to a function), that return value will only be available once that function is fully applied. In other words, for f:: (...) -> z where z is a primitive value (not a function), (...) can be as long as we like, if not full (...) are applied, we get f1::(...')->z To obtain z - the purpose f was written for - we need to pass full (...) although every function may be passed 1 (or even 0) args, n or (in)complete args has some meaning.

On 03.01.2016, at 22:30, Theodore Lief Gannon
wrote: sum :: Num a => a -> (a -> a) f :: (a -> a) -> (a -> a)
To really drive it home, let's play with synonyms.
type Endo' a = (a -> a)
Endo already exists as a newtype in Data.Monoid, thus Endo' here. Now:
sum :: Num a => a -> Endo' a f :: Endo' a -> Endo’ a
ok, this makes sense to me now – thank you very much for your patience. I’m trying to make the conclusion explicit, so please correct me if I’m wrong. if type checking of "f sum" assumes the type variable "a" to be of type Endo' in f, it concludes: sum takes Endo' to Endo' Endo' which looks equivalent to trying to construct an infinite type. The type checker seems not to worry about the more obvious arity/Num restriction of sum, which makes the result more interesting. More generally, if 1) f is a function that maps a function to a function of the same type (a -> a) -> (a -> a) 2) sum is a function that maps a value of type b to a function from (b -> b) 3) then their composition “f sum” would have two constraints: sum maps value a into function b = (a -> a) but f assumes equality between a and b, so that the required type would be one where a = (a -> a). which is possibly inconsistent, e.g. when it is interpreted as a definition of a set which has as its elements all sets of pairs of elements of that same set.
On 03.01.2016, at 22:50, Imants Cekusins
wrote: Could you think of a useful practical example of (a->a->a) . (a->a->a)
Good question. I indeed had nothing else in mind but to reason about functions. Which is quite practical if you are trying to understand haskell! I could imagine useful variants of function application, but that is pure speculation.
participants (4)
-
Imants Cekusins
-
Joel Neely
-
Julian Rohrhuber
-
Theodore Lief Gannon