Johannes Emerich | 6 Sep 17:04 2013
Picon

Unary functions and infix notation

As is well known, any binary function f can be turned into an infix operator by surrounding it with backticks:

    f a b   -- prefix application
    a `f` b -- infix application

It is then possible to take left and right sections, i.e. partially applying f:

    (a `f`) -- equivalent to \b -> a `f` b
    (`f` b) -- equivalent to \a -> a `f` b

This extends relatively naturally to functions of arity greater than two, where usage of a function in
infix notation produces a binary operator that returns a function of arity n-2.

Weirdly, however, infix notation can also be used for unary functions with polymorphic types, as the
following ghci session shows:

   Prelude> :t (`id` 1)
   (`id` 1) :: Num a => (a -> t) -> t
   Prelude> (`id` 1) (\y -> show y ++ ".what")
   "1.what"

Desugaring of an equivalent source file shows that id is applied to the anonymous function, which is then
applied to 1.

The following example of a function that is not polymorphic in its return type behaves closer to what I would
have expected: It does not work.

   Prelude> let z = (\y -> True) :: a -> Bool
   Prelude> :t (`z` True)

(Continue reading)

Brandon Allbery | 6 Sep 17:37 2013
Picon

Re: Unary functions and infix notation

On Fri, Sep 6, 2013 at 11:04 AM, Johannes Emerich <johannes <at> emerich.de> wrote:
Desugaring of an equivalent source file shows that id is applied to the anonymous function, which is then applied to 1.

The following example of a function that is not polymorphic in its return type behaves closer to what I would have expected: It does not work.

   Prelude> let z = (\y -> True) :: a -> Bool
   Prelude> :t (`z` True)

   <interactive>:1:2:
       The operator `z' takes two arguments,
       but its type `a0 -> Bool' has only one
       In the expression: (`z` True)

What is the purpose/reason for this behaviour?

Coming from another language, where functions aren't first class, you will probably be used to the notion that a function type is somehow different from any other type. You'll need to unlearn that for functional languages: function types are just as "real" as (Integer) is, and if I have a type variable somewhere which doesn't have constraints otherwise preventing it, that type variable can end up being (Integer) or (a -> a) or (Num c => c -> c -> c) or (Maybe [x]) or (Maybe (a -> a)) or any other (rank-1, i.e. no internal "forall"s) type.

(id) has the type (a -> a); in the use mentioned in the first quoted paragraph, this has unified (a) with (b -> b) to produce (id :: (b -> b) -> (b -> b)) in order for the whole expression to be typeable. In your second example, you don't have polymorphism "where it's needed" so it can't infer a type that will work.

--
brandon s allbery kf8nh                               sine nomine associates
allbery.b <at> gmail.com                                  ballbery <at> sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
John Lato | 6 Sep 17:43 2013
Picon

Re: Unary functions and infix notation

The observation that this only applies to functions with a polymorphic return type is key.

  id :: a -> a

This can be instantiated at

  id' :: (a->b) -> (a->b)
  id' :: (a->b) -> a -> b    -- these are the same

What this means is that id is a function with arity-2 whenever the first argument is arity-1, and generally id is a function of arity x+1 where x is the argument arity.  Incidentally, this is exactly the same as the ($) operator.

John L.


On Fri, Sep 6, 2013 at 10:04 AM, Johannes Emerich <johannes <at> emerich.de> wrote:
As is well known, any binary function f can be turned into an infix operator by surrounding it with backticks:

    f a b   -- prefix application
    a `f` b -- infix application

It is then possible to take left and right sections, i.e. partially applying f:

    (a `f`) -- equivalent to \b -> a `f` b
    (`f` b) -- equivalent to \a -> a `f` b

This extends relatively naturally to functions of arity greater than two, where usage of a function in infix notation produces a binary operator that returns a function of arity n-2.

Weirdly, however, infix notation can also be used for unary functions with polymorphic types, as the following ghci session shows:

   Prelude> :t (`id` 1)
   (`id` 1) :: Num a => (a -> t) -> t
   Prelude> (`id` 1) (\y -> show y ++ ".what")
   "1.what"

Desugaring of an equivalent source file shows that id is applied to the anonymous function, which is then applied to 1.

The following example of a function that is not polymorphic in its return type behaves closer to what I would have expected: It does not work.

   Prelude> let z = (\y -> True) :: a -> Bool
   Prelude> :t (`z` True)

   <interactive>:1:2:
       The operator `z' takes two arguments,
       but its type `a0 -> Bool' has only one
       In the expression: (`z` True)

What is the purpose/reason for this behaviour?

Thank you,
--Johannes
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Tom Ellis | 6 Sep 17:46 2013
Picon

Re: Unary functions and infix notation

On Fri, Sep 06, 2013 at 05:04:12PM +0200, Johannes Emerich wrote:
> Weirdly, however, infix notation can also be used for unary functions with
> polymorphic types, as the following ghci session shows:
> 
>    Prelude> :t (`id` 1)
>    (`id` 1) :: Num a => (a -> t) -> t
>    Prelude> (`id` 1) (\y -> show y ++ ".what")
>    "1.what"

There's nothing special about infix notation here:

    Prelude> :t \x -> id x 1
    \x -> id x 1 :: Num a => (a -> t) -> t
    Prelude> (\x -> id x 1) (\y -> show y ++ ".what")
    "1.what"

Tom
Wvv | 6 Sep 23:38 2013
Picon

Re: Unary functions and infix notation

But we can do next:

   Prelude> :set XPostfixOperators
   Prelude> let z = (\y -> True) :: a -> Bool 
   Prelude> :t (True `z`)

But still
`z` True   ~    \a -> a `z` True    ~   \a -> z a True
and `z` must be a function with minimum 2 arguments

--
View this message in context: http://haskell.1045720.n5.nabble.com/Unary-functions-and-infix-notation-tp5735766p5735807.html
Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Gmane