
I understand that the definitions introduced by 'let' can be recursive, even mutually recursive among several names. Why would you want to do that? I saw contrived examples, and wonder why the authors never show a realistic example. let b = f a c c = f a b in ... I see that makes sense in light of lazy evaluation: b is really an alias for a (recursive) function, not a value that needs to find fixed points. Is this used for common idioms and problem-solving approaches in Haskell? --John

On Thu, Apr 10, 2014, at 05:12 PM, John M. Dlugosz wrote:
I understand that the definitions introduced by 'let' can be recursive, even mutually recursive among several names. Why would you want to do that? I saw contrived examples, and wonder why the authors never show a realistic example.
let b = f a c c = f a b in ...
I am a bit confused by your question. I assume you know about the usefulness of recursion in general, and that your question is only about recursion in the context of a let-binding. But it seems to me that there is nothing particularly special about the let-binding context, as compared to, for example, the top level of a module. So what seems different about it to you? Your code snippet makes me think that perhaps you are specifically interested in definitions of non-function values. Is that so? -Karl

On Thu, Apr 10, 2014 at 07:12:25PM -0500, John M. Dlugosz wrote:
I understand that the definitions introduced by 'let' can be recursive, even mutually recursive among several names. Why would you want to do that? I saw contrived examples, and wonder why the authors never show a realistic example.
let b = f a c c = f a b in ...
I see that makes sense in light of lazy evaluation: b is really an alias for a (recursive) function, not a value that needs to find fixed points.
Is this used for common idioms and problem-solving approaches in Haskell?
I can't really point to any idiomatic use, or problem-solving approaches, but it is a terribly useful feature since one of the effects is that the order of introducing functions/values isn't significant. So you are free to write and structure your code in the manner that makes most sense to you. Having just ventured back into OCaml and dipping my toes in F# I immediately ran into errors caused by their non-recursive `let`, and the requirement to introduce values/types before use. /M -- Magnus Therning OpenPGP: 0xAB4DFBA4 email: magnus@therning.org jabber: magnus@therning.org twitter: magthe http://therning.org/magnus The results point out the fragility of programmer expertise: advanced programmers have strong expectations about what programs should look like, and when those expectations are violated--in seemingly innocuous ways--their performance drops drastically. -- Elliot Soloway and Kate Ehrlich

@John
Top level values have the attributes that you describe, recursion, mutual
recursion are possible.
So by using `let` and `where`, with out knowing any additional rules or
information, we can define values and functions which can be locally
scoped. Reducing the number of top level values by using locally scoped
vales often makes it easier to think about a problem.
You concern seems to be focused on the mutual recursion aspect however. Why
it is it useful in general? It allows for problems to be broken down in to
sub problems and solved separately.
With out mutually recursion or something similar if you had a problem that
need to recurse in two different ways, each which some times depended on
the other you would have to write it all in one large function.
An example where this is used in serious cod would be pipes and conduit.
Both handle stream processing of data.
Mutual recursion between (>>~) and (+>>)
http://hackage.haskell.org/package/pipes-4.1.1/docs/src/Pipes-Core.html#%3E%...
Look at the goRight and goLeft functions that are locally scoped with
`where` in either the `pipe` or `pipeL` functions.
https://hackage.haskell.org/package/conduit-1.1.0.1/docs/src/Data-Conduit-In...
So can help as a tool to break some problems in to subproblems and it is
used in serious code in Haskell
Patrick
On Fri, Apr 11, 2014 at 10:28 AM, Magnus Therning
On Thu, Apr 10, 2014 at 07:12:25PM -0500, John M. Dlugosz wrote:
I understand that the definitions introduced by 'let' can be recursive, even mutually recursive among several names. Why would you want to do that? I saw contrived examples, and wonder why the authors never show a realistic example.
let b = f a c c = f a b in ...
I see that makes sense in light of lazy evaluation: b is really an alias for a (recursive) function, not a value that needs to find fixed points.
Is this used for common idioms and problem-solving approaches in Haskell?
I can't really point to any idiomatic use, or problem-solving approaches, but it is a terribly useful feature since one of the effects is that the order of introducing functions/values isn't significant. So you are free to write and structure your code in the manner that makes most sense to you.
Having just ventured back into OCaml and dipping my toes in F# I immediately ran into errors caused by their non-recursive `let`, and the requirement to introduce values/types before use.
/M
-- Magnus Therning OpenPGP: 0xAB4DFBA4 email: magnus@therning.org jabber: magnus@therning.org twitter: magthe http://therning.org/magnus
The results point out the fragility of programmer expertise: advanced programmers have strong expectations about what programs should look like, and when those expectations are violated--in seemingly innocuous ways--their performance drops drastically. -- Elliot Soloway and Kate Ehrlich
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- Patrick Wheeler Patrick.John.Wheeler@gmail.com Patrick.J.Wheeler@rice.edu Patrick.Wheeler@colorado.edu

I don't mind recursive *functions*. It's recursive definition of single computed values that looked odd to me. Lazy evaluation makes all the difference. Looking at b= f a c c = f a b I was thinking, "how can it figure out what b and c need to be?" because I'm used to this meaning that it needs to come up with an actual value right now.

John,
That's classic mutual recursion. In your example, the values of b and c
depend entirely on f. For example what if
f = const a
Now b and c are obviously a and its not ambiguous. Similarly, mutually
recursive functions can compute values for b and c.
Do you have a similar issue with a definition like:
b = f a b
or is that fine? If so, why? If not, why not?
On Mon, Apr 14, 2014 at 11:24 AM, John M. Dlugosz
I don't mind recursive *functions*. It's recursive definition of single computed values that looked odd to me. Lazy evaluation makes all the difference. Looking at b= f a c
c = f a b I was thinking, "how can it figure out what b and c need to be?" because I'm used to this meaning that it needs to come up with an actual value right now.
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Mon, Apr 14, 2014 at 11:24 AM, John M. Dlugosz
I don't mind recursive *functions*. It's recursive definition of single
computed values that looked odd to me. Lazy evaluation makes all the difference. Looking at b= f a c
c = f a b I was thinking, "how can it figure out what b and c need to be?" because I'm used to this meaning that it needs to come up with an actual value right now.
To amplify Arjun's point, b = f a c c = f a b is equivalent to b = f a (f a b) c = f a (f a c) and now the mutual recursion that's troubling John vanishes. They become plain ol' self-recursive functions. I don't think mutual recursion is harder to make sense of than self-recursion. I think self-recursion appears easier than mutual recursion, but that's deceptive. It's actually just as hard!
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (6)
-
Arjun Comar
-
John M. Dlugosz
-
Karl Voelker
-
Kim-Ee Yeoh
-
Magnus Therning
-
Patrick Wheeler