partial application

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

partial application

Miguel Negrao
Hi list,

Is there a syntax in Haskell for partial application that would be something like this the following ?

f a b c d  = a +b+ c+ d

g = f _ 1 2 3

or the only way to do it is like below ?

g = (\x -> f x 1 2 3)

Also, hlint complains about top-level functions without type even if they are not exported out of the corresponding module. Is is really bad style not put type signatures in all top-level functions ? I really like the fact that haskell takes care of the type signatures for me.

best,
Miguel
http://www.friendlyvirus.org/miguelnegrao/






Reply | Threaded
Open this post in threaded view
|

partial application

Brent Yorgey-2
On Mon, Dec 03, 2012 at 12:28:08PM +0000, Miguel Negrao wrote:

> Hi list,
>
> Is there a syntax in Haskell for partial application that would be something like this the following ?
>
> f a b c d  = a +b+ c+ d
>
> g = f _ 1 2 3
>
> or the only way to do it is like below ?
>
> g = (\x -> f x 1 2 3)

Yes, a lambda is the only way to do it.

>  Also, hlint complains about top-level functions without type even
> if they are not exported out of the corresponding module. Is is
> really bad style not put type signatures in all top-level functions
> ? I really like the fact that haskell takes care of the type
> signatures for me.

Yes, it is bad style.  Let me give you two reasons why I always
encourage putting type signatures on all top-level functions.  Whether
they are exported or not really makes no difference.

  1. Writing the type signature for a function *first*, before
     implementing it, really helps a LOT in clarifying things in your
     own mind.  If you cannot write down the intended type of a
     function then you do not understand what it is supposed to do.
     If you do not understand what it is supposed to do then how do
     you expect to be able to implement it?

  2. Suppose you make a mistake when implementing a function.  If you
     don't give a type signature, it's possible that GHC will infer
     some type for it anyway (but not the type you intended!).  Now
     you will not get an error until further down the line when you
     use that function somewhere else.  And what's more, the error
     will not tell you anything about the real problem.  It will just
     say "X does not match Y on line 297" and you will have to do a
     lot of work to figure out that the real problem is that you
     messed up in implementing function foo on line 43.  But if you
     had put a type signature on foo in the first place, you would
     have gotten an error immediately.

-Brent


Reply | Threaded
Open this post in threaded view
|

partial application

Brent Yorgey-2
On Mon, Dec 03, 2012 at 03:20:41PM +0000, Miguel Negrao wrote:

>
> A 03/12/2012, ?s 12:53, Brent Yorgey escreveu:
> >> Is there a syntax in Haskell for partial application that would be something like this the following ?
> >>
> >> f a b c d  = a +b+ c+ d
> >>
> >> g = f _ 1 2 3
> > Yes, a lambda is the only way to do it.
>
> Given how compact haskell?s syntax can be, is there a reason why implementing such placeholders is not a good idea for haskell ?

Yes: it would introduce horrible ambiguity.  Consider

  (f (g _ 1 2))

Does it mean

  (f (\x -> g x 1 2))

or

  (\x -> f (g x 1 2))

?  I don't know of any good reason to prefer one over the other.  Any
rule you come up with is likely to have other weird corner cases you
hadn't considered.  As I understand it, Scala actually does have this
feature, along with lots of confusing, ugly, ad-hoc rules to
disambiguate situations like the above.

> >  2. Suppose you make a mistake when implementing a function.  If you
> >     don't give a type signature, it's possible that GHC will infer
> >     some type for it anyway (but not the type you intended!).  Now
> >     you will not get an error until further down the line when you
> >     use that function somewhere else.  And what's more, the error
> >     will not tell you anything about the real problem.  It will just
> >     say "X does not match Y on line 297" and you will have to do a
> >     lot of work to figure out that the real problem is that you
> >     messed up in implementing function foo on line 43.  But if you
> >     had put a type signature on foo in the first place, you would
> >     have gotten an error immediately.

>  Ok, I see your points. Number 2 does happen to me from time to
> time, at which point I go back to the a point where the code worked
> and introduce the type signatures with hlint, so yeah doing the
> signatures would save me from having to do that.  Sometimes I know
> how to write a function but I don?t know how to write the type
> signature because they are too complicated for my still reduced
> knowledge of haskell, for instance, I don?t know when I need to use
> the forall thing, which hlint sometimes introduces when it produces
> the type signatures. Perhaps the problem might be that I should be
> using less top-level functions and defining some of those functions
> where they are used ? A lot of my top-level functions are used only
> in one place in the code, I just code them as top-level so that I
> can test them in ghci if I need to.

No, I don't think using less top-level functions will solve anything.
In the case where you don't know how to write a type because it is too
complex, or requires features you don't understand, I think it is
reasonable to write it, ask GHCI for its type signature, make sure it
looks reasonable, and then add it to your file.  But I would hope this
situation makes up a minority of cases.  One could also question the
wisdom of writing code that requires type system features you don't
understand.

-Brent


Reply | Threaded
Open this post in threaded view
|

partial application

Keshav Kini
In reply to this post by Brent Yorgey-2
Brent Yorgey <byorgey at seas.upenn.edu> writes:

> On Mon, Dec 03, 2012 at 12:28:08PM +0000, Miguel Negrao wrote:
>> Is there a syntax in Haskell for partial application that would be something like this the following ?
>>
>> f a b c d  = a +b+ c+ d
>>
>> g = f _ 1 2 3
>>
>> or the only way to do it is like below ?
>>
>> g = (\x -> f x 1 2 3)
>
> Yes, a lambda is the only way to do it.

In the case where you have fewer (specifically two) variables, you can
also use `flip`::

   f a b = a / b

   -- g = f _ 2 can be written as:
   g = flip f 2

-Keshav



Reply | Threaded
Open this post in threaded view
|

partial application

Keshav Kini
In reply to this post by Brent Yorgey-2
Brent Yorgey <byorgey at seas.upenn.edu> writes:

> On Mon, Dec 03, 2012 at 03:20:41PM +0000, Miguel Negrao wrote:
>>
>> A 03/12/2012, ?s 12:53, Brent Yorgey escreveu:
>> >> Is there a syntax in Haskell for partial application that would be something like this the following ?
>> >>
>> >> f a b c d  = a +b+ c+ d
>> >>
>> >> g = f _ 1 2 3
>> > Yes, a lambda is the only way to do it.
>>
>> Given how compact haskell?s syntax can be, is there a reason why implementing such placeholders is not a good idea for haskell ?
>
> Yes: it would introduce horrible ambiguity.  Consider
>
>   (f (g _ 1 2))
>
> Does it mean
>
>   (f (\x -> g x 1 2))
>
> or
>
>   (\x -> f (g x 1 2))
>
> ?  I don't know of any good reason to prefer one over the other.  Any
> rule you come up with is likely to have other weird corner cases you
> hadn't considered.  As I understand it, Scala actually does have this
> feature, along with lots of confusing, ugly, ad-hoc rules to
> disambiguate situations like the above.

Another data-point: Mathematica also has this feature, if I correctly
understand the above posts [1]. The examples you gave would look like::

    (f (g _ 1 2)) ~= f[g[#1, 1, 2]]&

    (f (\x -> g x 1 2)) ~= f[g[#1, 1, 2]&]

    (\x -> f (g x 1 2)) ~= f[g[#1, 1, 2]]&

So it seems the ambiguity is resolved by having this scope-specifying
symbol '&'.

[1] http://reference.wolfram.com/mathematica/tutorial/PureFunctions.html

-Keshav



Reply | Threaded
Open this post in threaded view
|

partial application

Peter Hall
In reply to this post by Brent Yorgey-2
> >
> > g = (\x -> f x 1 2 3)
>
> Yes, a lambda is the only way to do it.

This is not exactly the same thing, but if you have a function that accepts
only two arguments, you can use `flip` to partially apply with the other
one:

f a b = a ++ b
g = (flip f) "xyz"

g "abc" -- "abcxyz"

To extend that to functions with more parameters, you'd have to create an
equivalent of `flip` for each arity, and the desired permutations might be
more complicated than just reversing them. Still, in the two-argument case,
flip can often be cleaner than a lambda.

Peter


On 3 December 2012 12:53, Brent Yorgey <byorgey at seas.upenn.edu> wrote:

> On Mon, Dec 03, 2012 at 12:28:08PM +0000, Miguel Negrao wrote:
> > Hi list,
> >
> > Is there a syntax in Haskell for partial application that would be
> something like this the following ?
> >
> > f a b c d  = a +b+ c+ d
> >
> > g = f _ 1 2 3
> >
> > or the only way to do it is like below ?
> >
> > g = (\x -> f x 1 2 3)
>
> Yes, a lambda is the only way to do it.
>
> >  Also, hlint complains about top-level functions without type even
> > if they are not exported out of the corresponding module. Is is
> > really bad style not put type signatures in all top-level functions
> > ? I really like the fact that haskell takes care of the type
> > signatures for me.
>
> Yes, it is bad style.  Let me give you two reasons why I always
> encourage putting type signatures on all top-level functions.  Whether
> they are exported or not really makes no difference.
>
>   1. Writing the type signature for a function *first*, before
>      implementing it, really helps a LOT in clarifying things in your
>      own mind.  If you cannot write down the intended type of a
>      function then you do not understand what it is supposed to do.
>      If you do not understand what it is supposed to do then how do
>      you expect to be able to implement it?
>
>   2. Suppose you make a mistake when implementing a function.  If you
>      don't give a type signature, it's possible that GHC will infer
>      some type for it anyway (but not the type you intended!).  Now
>      you will not get an error until further down the line when you
>      use that function somewhere else.  And what's more, the error
>      will not tell you anything about the real problem.  It will just
>      say "X does not match Y on line 297" and you will have to do a
>      lot of work to figure out that the real problem is that you
>      messed up in implementing function foo on line 43.  But if you
>      had put a type signature on foo in the first place, you would
>      have gotten an error immediately.
>
> -Brent
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20121205/98eeb691/attachment.htm>