Brent Yorgey <byorgey <at> seas.upenn.edu> writes:
>> On Sat, Feb 28, 2009 at 05:19:03PM +0000, Will Ness wrote:
> > <j.romildo <at> gmail.com> writes:
> >
> > >
> > > Hello.
> > >
> > > Is there any non-recursive binding expression in Haskell?
> > >
> > > Something that would allow me to write, for instance,
> > >
> > > test = let' xs = [] in
> > > let' xs = 3 : xs in
> > > let' xs = 8 : xs in
> > > let' xs = 7 : xs in
> > > xs
> >
> > Well, it's not a nice thing to do (probably), but you can write
> >
> > test = head $
> > do xs <- [ [] ]
> > xs <- [ 3:xs ]
> > xs <- [ 8:xs ]
> > xs <- [ 7:xs ]
> > return xs
> >
>> The correct answer is no. Life is pain. Anyone who says otherwise is
> selling something. ;)
>> Assignment in Haskell is not destructive update---it assigns a name to
> a value, and they become one flesh, until parted by death (i.e. the
> end of their lexical scope). The only reason Will's code works is
> that each line creates a new lexical scope, and each xs shadows the
> previous one.
That's what I understood the OP wanted - Scheme's LET, not LETREC, allowing for
shadowing. I was suprised let-statement in do chain didn't work that way. I
expected it to be equivalent to a kind of code above, since each new line in do
block represents a nested function in explicit bind notation, and nested
function binding definitely provides for non-recursive let kind of argument
binding, with shadowing.
I thought the whole point of having special let statement in do notation was
not to have to write the kind of code above with singleton lists. Since we have
shadowing there, it should've been so in let-statements too. Isn't it?
>> To do what you want, you have to give each thing a new name, something
> like this:
>> test = let xs = []
> xs' = 3 : xs
> xs'' = 8 : xs'
> xs''' = 7 : xs''
> in xs'''
>> "But this is horribly painful!" you cry. Of course it is! Giving
> names to things you don't want to keep is always painful (like when
> your child names the almost-dead raccoon you find in the street, which
> is just going to die or be given to an animal shelter anyway).
>> So, why not just avoid naming things you don't want?
>> test = (7:) . (8:) . (3:) $ []
>> Ah, that's better! We just thread some intermediate values through a
> chain of composed functions. Each function does its little bit of
> modification and passes the intermediate value along to the next
> function, and the intermediate values are never given names.
>> -Brent
>
BTW could there be a use for something like
infixl 1 #
x # f = f x -- (#) = flip ($)
to have the direct data flow reflected in our code, so that your code would
become
test = [] # (3:) # (8:) # (7:)
maybe sometimes it's more natural to think of data being "piped through" the
chain of functions, and to write them down in forward, not reverse order of
application?