Re: [Haskell-beginners] Closure

Williams
wrote: Good morning
What is a closure and, what purpose does it serve?
This seems like a good explanation: http://www.haskell.org/haskellwiki/Closure
/M
Williams
wrote: How does a closure differ from a binding? An example or two would be nice. :-)
Sincerely, MJW

On Wed, Jul 29, 2009 at 09:11:02PM +0100, Matthew J. Williams wrote:
Williams
wrote: Good morning
What is a closure and, what purpose does it serve?
This seems like a good explanation: http://www.haskell.org/haskellwiki/Closure
/M
Williams
wrote: How does a closure differ from a binding? An example or two would be nice. :-)
A closure is essentially a binding, *together with* the enclosing environment---the idea being that the binding may refer (via free variables) to things in its environment. The ability to have closures is absolutely crucial to having first-class functions. For example, consider this function: mkAdder :: Int -> (Int -> Int) mkAdder y = \x -> x + y mkAdder takes an Int as an argument, and returns a function (Int -> Int) as a result. But take a look at the function it returns: \x -> x + y has a free variable (y) which refers to its environment. So really what you get when you call mkAdder with a particular argument (say, 3) is a closure, containing the function \x -> x + y together with the environment (y = 3). Of course, hopefully you have realized that mkAdder is really just (+), written in a funny way! So this isn't a contrived example; closures are quite fundamental in Haskell. With that said, on some level the idea of a closure is really just an implementation detail---I wouldn't say that understanding it is of fundamental importance in learning Haskell. But learning things never hurts (except when it does). Hope this helps! -Brent

In article <20090729202442.GA8017@seas.upenn.edu>, Brent Yorgey wrote:
With that said, on some level the idea of a closure is really just an implementation detail---I wouldn't say that understanding it is of fundamental importance in learning Haskell. But learning things never hurts (except when it does).
So it sounds correct to say that a closure is a function that brings an environment with it, such as variables defined outside of it. With this ability, we can construct functions on the fly because a function can return a closure which is amended and, say, returned again another closure more fully specified.

In article
In article <20090729202442.GA8017@seas.upenn.edu>, Brent Yorgey wrote:
With that said, on some level the idea of a closure is really just an implementation detail---I wouldn't say that understanding it is of fundamental importance in learning Haskell. But learning things never hurts (except when it does).
So it sounds correct to say that a closure is a function that brings an environment with it, such as variables defined outside of it.
With this ability, we can construct functions on the fly because a function can return a closure which is amended and, say, returned again another closure more fully specified.
Hello. This was actually a request for comments. Though I didn't say it. Does that sound correct? Any comments? Thanks much.

Daniel Bastos wrote:
So it sounds correct to say that a closure is a function that brings an environment with it, such as variables defined outside of it.
With this ability, we can construct functions on the fly because a function can return a closure which is amended and, say, returned again another closure more fully specified.
Hello. This was actually a request for comments. Though I didn't say it. Does that sound correct? Any comments? Thanks much.
Yes, that's pretty much correct. The simplest example of a closure is indeed foo = add 3 where add = \x y -> x + y Reduction to weak head normal form yields foo = let x = 3 in \y -> x + y which means that foo is a function \y -> x + y paired with the value of the free variable x . Note that closures are an implementation detail. From a semantic point of view, add 3 can readily be understood as an ordinary function. Regards, apfelmus -- http://apfelmus.nfshost.com

In article
The simplest example of a closure is indeed
foo = add 3
where
add = \x y -> x + y
Question. This is actually equal to add x y = x + y But you wrote in terms of \. Why such preference?
Reduction to weak head normal form yields
foo = let x = 3 in \y -> x + y
which means that foo is a function \y -> x + y paired with the value of the free variable x .
I see.
Note that closures are an implementation detail. From a semantic point of view, add 3 can readily be understood as an ordinary function.
This makes sense. Because, even in a language like C, a similar effect can be achieved, no? For example int plus(int x, int y) { return x + y; } int plus3(int y) { plus(3, y); } So, what I can't do in C, besides almost everything I can't do, is to do this nicely like I do in Haskell. But we don't call this a closure. In fact, we say C does not allow for closures. So what am I missing?

Am Samstag 15 August 2009 18:07:08 schrieb Daniel Bastos:
In article
, Heinrich Apfelmus wrote:
The simplest example of a closure is indeed
foo = add 3
where
add = \x y -> x + y
Question. This is actually equal to
add x y = x + y
But you wrote in terms of \. Why such preference?
Reduction to weak head normal form yields
foo = let x = 3 in \y -> x + y
which means that foo is a function \y -> x + y paired with the value of the free variable x .
I see.
Note that closures are an implementation detail. From a semantic point of view, add 3 can readily be understood as an ordinary function.
This makes sense. Because, even in a language like C, a similar effect can be achieved, no? For example
int plus(int x, int y) { return x + y; }
int plus3(int y) { plus(3, y); }
So, what I can't do in C, besides almost everything I can't do, is to do this nicely like I do in Haskell. But we don't call this a closure. In fact, we say C does not allow for closures. So what am I missing?
You can't do cmp :: a -> a -> a -> Ordering cmp pivot x y = ... funkyFun :: (a -> a -> a -> Ordering) -> [a] -> [a] funkyFun _ [] = [] funkyFun c (x:xs) = x:sortBy (c x) xs main = do args <- getArgs print $ funkyFun cmp (some pseudorandom list depending on args) in C (at least not without some black magic). The plus3 example is a "closure" which is hardcoded and available at compile time. I think, to say that a language allows closures means it allows closures determined at run time.

In article <200908151831.14649.daniel.is.fischer@web.de>, Daniel Fischer wrote:
The plus3 example is a "closure" which is hardcoded and available at compile time. I think, to say that a language allows closures means it allows closures determined at run time.
Hm. But does Haskell allow me to define a function at run time? I know Lisp can, since a function is just a data structure which we can put together at run time. But how about Haskell?

Am Samstag 15 August 2009 19:06:42 schrieb Daniel Bastos:
In article <200908151831.14649.daniel.is.fischer@web.de>,
Daniel Fischer wrote:
The plus3 example is a "closure" which is hardcoded and available at compile time. I think, to say that a language allows closures means it allows closures determined at run time.
Hm. But does Haskell allow me to define a function at run time? I know Lisp can, since a function is just a data structure which we can put together at run time. But how about Haskell?
Depends on how you interpret it. In the sense of ... let foo = \y -> f x y in map foo list where the value of x is supplied at run time (and more complicated constructions depending on run time values), sure. If you write a good parser, you can also do putStrLn "Please enter function code:" code <- getLine let fun = parseFunction code use fun -- may segfault if the entered code isn't good In which (other) ways can you construct functions at run time in Lisp?

In article <200908152114.40077.daniel.is.fischer@web.de>, Daniel Fischer wrote:
[Does] Haskell allow me to define a function at run time? I know Lisp can, since a function is just a data structure which we can put together at run time. But how about Haskell?
[...]
If you write a good parser, you can also
do putStrLn "Please enter function code:" code <- getLine let fun = parseFunction code use fun -- may segfault if the entered code isn't good
In which (other) ways can you construct functions at run time in Lisp?
None. I guess the only difference, if so considered, is that since Lisp is so much syntactically simpler, it's easy to write a parser for it, and I guess most implementations already bring one for ya. And that's nice. It allows for the code that write code, which sounds great. But anyway, my interest here was understanding Haskell better, which I now do. Thanks for all inputs in this subthread.

On Aug 15, 2009, at 12:07 , Daniel Bastos wrote:
This makes sense. Because, even in a language like C, a similar effect can be achieved, no? For example
int plus(int x, int y) { return x + y; }
int plus3(int y) { plus(3, y); }
So, what I can't do in C, besides almost everything I can't do, is to do this nicely like I do in Haskell. But we don't call this a closure. In fact, we say C does not allow for closures. So what am I missing?
In C you have to declare it. In Haskell you can just do it on the fly:
map (add 3) [1..10]
or indeed
map (+3) [1..10]
(The above is actually a "section", a closure created from an infix function. The difference is that I can specify either side of the operator, whereas to specify arguments other than the first for a regular function I must either coerce it into infix with `` or use the "flip" function to rearrange arguments.) -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

In article <1B14D870-7355-4EFD-B0C6-026109AB4F87@ece.cmu.edu>, Brandon S. Allbery KF8NH wrote:
In C you have to declare it.
The word would be `define'?
In Haskell you can just do it on the fly:
map (add 3) [1..10]
I see. Just like we can create an integer on the fly in C, in Haskell we can create functions on the fly. I guess that's quite a difference.
or indeed
map (+3) [1..10]
(The above is actually a "section", a closure created from an infix function. The difference is that I can specify either side of the operator, whereas to specify arguments other than the first for a regular function I must either coerce it into infix with `` or use the "flip" function to rearrange arguments.)
And is this mere syntax sugar?

Daniel Bastos wrote:
Heinrich Apfelmus wrote:
The simplest example of a closure is indeed
foo = add 3
where
add = \x y -> x + y
Question. This is actually equal to
add x y = x + y
But you wrote in terms of \. Why such preference?
I wanted to emphasize that add is a value just like 4 or "baz" , i.e. that it's not very different from writing say add = "baz"
Note that closures are an implementation detail. From a semantic point of view, add 3 can readily be understood as an ordinary function.
This makes sense. Because, even in a language like C, a similar effect can be achieved, no? For example
int plus(int x, int y) { return x + y; }
int plus3(int y) { plus(3, y); }
So, what I can't do in C, besides almost everything I can't do, is to do this nicely like I do in Haskell. But we don't call this a closure. In fact, we say C does not allow for closures. So what am I missing?
A litmus test for being a functional language is the ability to define function composition f . g = \x -> f (g x) This is not possible in C; mainly because functions cannot be defined locally, they have to be declared at the top-level. (I think this test is due to Lennart Augustsson, but I can't find a reference on the web right now.) Hm... this means that Brent's example foo x = add where add y = x + y is actually a much better demonstration of a closure than the one I gave. Yes, I think this one is impossible to write in C. Regards, apfelmus -- http://apfelmus.nfshost.com
participants (6)
-
Brandon S. Allbery KF8NH
-
Brent Yorgey
-
Daniel Bastos
-
Daniel Fischer
-
Heinrich Apfelmus
-
Matthew J. Williams