[Haskell-cafe] Lambda-case / lambda-if

170 views
Skip to first unread message

Max Bolingbroke

unread,
Oct 2, 2010, 2:23:25 PM10/2/10
to haskell-cafe
Hi Cafe,

I implemented the proposed Haskell' feature lambda-case/lambda-if [1]
during the Haskell Implementors Workshop yesterday for a bit of fun.
The patches are online [2, 3].

The feature is demonstrated in this GHCi session:

$ inplace/bin/ghc-stage2 --interactive -XLambdaCase
GHCi, version 7.1.20101002: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> (if then "Haskell" else "Cafe") False
"Cafe"
Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
"One"
Prelude> :q

Do you like this feature and think it would be worth incorporating
this into GHC? Or is it too specialised to be of use? If there is
enough support, I'll create a ticket and see what GHC HQ make of it.

Max

[1] http://hackage.haskell.org/trac/haskell-prime/ticket/41
[2] http://www.omega-prime.co.uk/files/LambdaCase-Testsuite.patch
[3] http://www.omega-prime.co.uk/files/LambdaCase-Compiler.patch
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Colin Paul Adams

unread,
Oct 2, 2010, 2:29:56 PM10/2/10
to Max Bolingbroke, haskell-cafe
>>>>> "Max" == Max Bolingbroke <batters...@hotmail.com> writes:

Prelude> (if then "Haskell" else "Cafe") False

Max> "Cafe"

My reaction is to ask:

Can you write this as:

(if then else) False "Haskell" "Cafe"

?
--
Colin Adams
Preston Lancashire
() ascii ribbon campaign - against html e-mail
/\ www.asciiribbon.org - against proprietary attachments

Henning Thielemann

unread,
Oct 2, 2010, 2:33:18 PM10/2/10
to Max Bolingbroke, haskell-cafe

On Sat, 2 Oct 2010, Max Bolingbroke wrote:

> Hi Cafe,
>
> I implemented the proposed Haskell' feature lambda-case/lambda-if [1]
> during the Haskell Implementors Workshop yesterday for a bit of fun.
> The patches are online [2, 3].
>
> The feature is demonstrated in this GHCi session:
>
> $ inplace/bin/ghc-stage2 --interactive -XLambdaCase
> GHCi, version 7.1.20101002: http://www.haskell.org/ghc/ :? for help
> Loading package ghc-prim ... linking ... done.
> Loading package integer-gmp ... linking ... done.
> Loading package base ... linking ... done.
> Loading package ffi-1.0 ... linking ... done.
> Prelude> (if then "Haskell" else "Cafe") False
> "Cafe"
> Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
> "One"
> Prelude> :q
>
> Do you like this feature and think it would be worth incorporating
> this into GHC? Or is it too specialised to be of use? If there is
> enough support, I'll create a ticket and see what GHC HQ make of it.

Nice! Concerning if-then-else I would more like to see an according
function to go to Data.Bool, then we won't need more syntactic sugar like
if-then-else. However the lambda-case would be useful for me.

Henning Thielemann

unread,
Oct 2, 2010, 2:35:52 PM10/2/10
to Colin Paul Adams, haskell-cafe

On Sat, 2 Oct 2010, Colin Paul Adams wrote:

>>>>>> "Max" == Max Bolingbroke <batters...@hotmail.com> writes:
>
> Prelude> (if then "Haskell" else "Cafe") False
> Max> "Cafe"
>
> My reaction is to ask:
>
> Can you write this as:
>
> (if then else) False "Haskell" "Cafe"
>
> ?

Sure:

ifThenElse :: Bool -> a -> a -> a
ifThenElse True x _ = x
ifThenElse False _ y = y

Prelude> ifThenElse False "Haskell" "Cafe"

(I have done this in utility-ht, and called it "if'".)

Christopher Done

unread,
Oct 2, 2010, 3:13:57 PM10/2/10
to Max Bolingbroke, haskell-cafe
On 2 October 2010 20:23, Max Bolingbroke <batters...@hotmail.com> wrote:
> Do you like this feature and think it would be worth incorporating
> this into GHC? Or is it too specialised to be of use? If there is
> enough support, I'll create a ticket and see what GHC HQ make of it.

Nice work! I like it and have wanted it for a while, and I know many
in the #haskell IRC channel would like it. The case is especially
useful. Maybe the if is only useful sometimes.

A benefit for lambda-case that I'll throw in the mix is:

main = do
args <- getArgs
case args of
[path] -> do exists <- doesFileExist filepath
if exists
then readFile filepath >>= putStrLn
else error "file does not exist"
_ -> error "usage: foo <filename>"

becomes:

main = do
getArgs >>= case of
[path] -> doesFileExist filepath
>>= if then readFile filepath >>= putStrLn
else error "file does not exist"
_ -> error "usage: foo <filename>"

There's nothing more annoying than having to introduce intermediate
bindings when you're going to immediate pattern match against it
immediately and never use it again. It's both annoying to have to
think of a variable name that makes sense and is not in scope or will
be in scope, and annoying to type it out, and it's just ugly. This is
*not* a special-case, it happens all the time and it's one of the few
things in the syntax I wish could be updated.

I vote yes, yes, and double yes!

Christopher Done

unread,
Oct 2, 2010, 3:18:08 PM10/2/10
to Max Bolingbroke, haskell-cafe
I just had a look at hpaste.org, and, amusingly, the first paste has this:

down <- openLazyURI "http://list.iblocklist.com/?list=bt_level1"
case down of
Left _ -> error "Could not download file"
Right bs -> do input <- bs
...

I can collect a huge list of instances of this annoying pattern from
Hackage and Google Code Search if it will encourage GHC HQ to make it
an extension.

Ozgur Akgun

unread,
Oct 2, 2010, 3:20:17 PM10/2/10
to Henning Thielemann, haskell-cafe
On 2 October 2010 19:33, Henning Thielemann <lem...@henning-thielemann.de> wrote:

On Sat, 2 Oct 2010, Max Bolingbroke wrote:

... lambda-case/lambda-if ...

Nice! Concerning if-then-else I would more like to see an according function to go to Data.Bool, then we won't need more syntactic sugar like if-then-else. However the lambda-case would be useful for me.  

And I was just reading this entry in the wiki: http://www.haskell.org/haskellwiki/If-then-else

Best,
Ozgur

Jan Christiansen

unread,
Oct 2, 2010, 3:27:01 PM10/2/10
to Henning Thielemann, Colin Paul Adams, haskell-cafe

On 02.10.2010, at 20:35, Henning Thielemann wrote:

>
> On Sat, 2 Oct 2010, Colin Paul Adams wrote:

>> Prelude> (if then "Haskell" else "Cafe") False
>> Max> "Cafe"
>>
>> My reaction is to ask:
>>
>> Can you write this as:
>>
>> (if then else) False "Haskell" "Cafe"
>>
>> ?
>
> Sure:
>
> ifThenElse :: Bool -> a -> a -> a
> ifThenElse True x _ = x
> ifThenElse False _ y = y
>
> Prelude> ifThenElse False "Haskell" "Cafe"


You can use a similar approach for case expressions ; )


import Prelude hiding ( catch )
import System.IO.Unsafe ( unsafePerformIO )
import Control.Exception ( catch, evaluate, PatternMatchFail )


caseOf :: a -> [a -> b] -> b
caseOf x = unsafePerformIO . firstMatch . map ($x)

firstMatch :: [a] -> IO a
firstMatch (x:xs) = catch (evaluate x) (handlePatternFail (firstMatch
xs))

handlePatternFail :: a -> PatternMatchFail -> a
handlePatternFail x _ = x


test = (flip caseOf [\1 -> "One", \_ -> "Not-one"]) 1


Well, to tell the truth this does not work correctly as the following
example shows.

test2 = (flip caseOf [\1 -> ((\2 -> "One") 3), \_ -> "Not-one"]) 1

Felipe Lessa

unread,
Oct 2, 2010, 3:32:23 PM10/2/10
to chri...@googlemail.com, haskell-cafe
On Sat, Oct 2, 2010 at 4:13 PM, Christopher Done
<chri...@googlemail.com> wrote:
> There's nothing more annoying than having to introduce intermediate
> bindings when you're going to immediate pattern match against it
> immediately and never use it again. It's both annoying to have to
> think of a variable name that makes sense and is not in scope or will
> be in scope, and annoying to type it out, and it's just ugly. This is
> *not* a special-case, it happens all the time and it's one of the few
> things in the syntax I wish could be updated.
>
> I vote yes, yes, and double yes!

I wholly agree with Christopher and for the same reason, +1.

Thanks,

--
Felipe.

Brandon S Allbery KF8NH

unread,
Oct 2, 2010, 4:40:59 PM10/2/10
to haskel...@haskell.org
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 10/2/10 15:27 , Jan Christiansen wrote:
> You can use a similar approach for case expressions ; )

There are several better (that is, not using unsafePerformIO) versions at
http://haskell.org/haskellwiki/Case .

- --
brandon s. allbery [linux,solaris,freebsd,perl] all...@kf8nh.com
system administrator [openafs,heimdal,too many hats] all...@ece.cmu.edu
electrical and computer engineering, carnegie mellon university KF8NH
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.10 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkynmNsACgkQIn7hlCsL25XbOgCfdjFrXdR3PWJvPUif7VVfZZak
lOcAoMpp6l1+XOxU6vwCT+sgLI94l3Kx
=+gFp
-----END PGP SIGNATURE-----

wren ng thornton

unread,
Oct 2, 2010, 7:16:46 PM10/2/10
to haskell-cafe
On 10/2/10 3:13 PM, Christopher Done wrote:
> There's nothing more annoying than having to introduce intermediate
> bindings when you're going to immediate pattern match against it
> immediately and never use it again. It's both annoying to have to
> think of a variable name that makes sense and is not in scope or will
> be in scope, and annoying to type it out, and it's just ugly. This is
> *not* a special-case, it happens all the time and it's one of the few
> things in the syntax I wish could be updated.

+1.

In Mark Jones' new language, Habit, they have monadic versions of case
and if-then-else for precisely this reason.

I'm not sure if the (case of {...}) syntax is the best one to use for
this feature, but I'd love to get rid of those intermediate names for
monadic case expressions.

--
Live well,
~wren

Max Bolingbroke

unread,
Oct 2, 2010, 7:59:22 PM10/2/10
to haskell-cafe
Thanks to everyone who replied - it looks like this feature is enough
in demand that GHC HQ may want to accept it. I've created a ticket at
http://hackage.haskell.org/trac/ghc/ticket/4359

Conal Elliott

unread,
Oct 3, 2010, 7:38:13 PM10/3/10
to Max Bolingbroke, haskell-cafe
I like it!

Are the other sections available as well, e.g.,

    (if False then else "Cafe") "Haskell" --> "Cafe"

- Conal

Ketil Malde

unread,
Oct 4, 2010, 3:30:48 AM10/4/10
to Max Bolingbroke, haskell-cafe
Max Bolingbroke <batters...@hotmail.com> writes:

> [1] http://hackage.haskell.org/trac/haskell-prime/ticket/41

I tried to find anything about lambda-if in there, but failed (Trac and
I aren't on very friendly terms, so it's probably my fault). Is there
more information about the rationale and use cases for this?

> Prelude> (if then "Haskell" else "Cafe") False
> "Cafe"

Presumably, this extends to

> Prelude> (if False then else "Cafe") "Haskell"
> "Cafe"

and

> Prelude> (if then "Haskell" else) False "Cafe"
> "Cafe"

as well?

My gut reaction is that this doesn't buy a whole lot, and that it is
verbose and not very readable. Any examples where this is a win?

> Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
> "One"
> Prelude> :q

"case of" looks a bit weird, but I like the points brought up about
avoiding to name a one-use variable (e.g., getArgs >>= case of ...)
AFACS, this isn't easily implemented in Haskell either.

-k
--
If I haven't seen further, it is by standing in the footprints of giants

Bulat Ziganshin

unread,
Oct 4, 2010, 4:55:57 AM10/4/10
to Ketil Malde, haskell-cafe
Hello Ketil,

Monday, October 4, 2010, 11:30:48 AM, you wrote:
>> Prelude> (if then "Haskell" else "Cafe") False

lambda-if is easily implemented in terms of usual functions.
and we even have one named bool:

bool: Bool -> a -> a -> a

lambda-case cannot be implemented as a function since we need
matching ability of "case"


--
Best regards,
Bulat mailto:Bulat.Z...@gmail.com

Christopher Done

unread,
Oct 4, 2010, 6:05:55 AM10/4/10
to Bulat Ziganshin, haskell-cafe
On 4 October 2010 10:55, Bulat Ziganshin <bulat.z...@gmail.com> wrote:
> Hello Ketil,
>
> Monday, October 4, 2010, 11:30:48 AM, you wrote:
>>> Prelude> (if then "Haskell" else "Cafe") False
>
> lambda-if is easily implemented in terms of usual functions.
> and we even have one named bool:
>
> bool: Bool -> a -> a -> a

I agree, in fact I have bool here:
http://hackage.haskell.org/packages/archive/higherorder/0.0/doc/html/Data-Bool-Higher.html

And the corresponding other types:

bool :: (a -> b) -> (a -> b) -> (a -> Bool) -> a -> b
list :: b -> ([a] -> b) -> [a] -> b
maybe :: b -> (a -> b) -> Maybe a -> b

But the case is especially useful for pattern matching.

Donn Cave

unread,
Oct 4, 2010, 11:04:21 AM10/4/10
to haskell-cafe
Quoth Ketil Malde <ke...@malde.org>,
> Max Bolingbroke <batters...@hotmail.com> writes:
...

>> Prelude> (if then "Haskell" else "Cafe") False
>> "Cafe"
>
> Presumably, this extends to
>
>> Prelude> (if False then else "Cafe") "Haskell"
>> "Cafe"
>
> and
>
>> Prelude> (if then "Haskell" else) False "Cafe"
>> "Cafe"
>
> as well?

I think you're not the first to ask. Just out of curiosity, or is
there a use for these variations?

The reason for the initially proposed construct seems clear enough
to me, it's very much like `case'. The difference is that of course
it's limited to True & False, so would naturally be used more with
more `composition', e.g.

getargs >>= if then beTrue else beFalse . (==) ["-t"]

... and thus will quickly become unreadable with less trivial components.

Donn

Roel van Dijk

unread,
Oct 4, 2010, 1:11:18 PM10/4/10
to Max Bolingbroke, haskell-cafe
I really like the lambda-case. There are dozens of places in my code
where I could use it.

Not so sure about the lambda-if. It is just as easily done using an
ordinary function.

lambda-case: +1
lambda-if: neutral

Richard O'Keefe

unread,
Oct 4, 2010, 5:11:04 PM10/4/10
to Ketil Malde, haskell-cafe

On 4/10/2010, at 8:30 PM, Ketil Malde wrote:
>
>> Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
>> "One"
>> Prelude> :q
>
> "case of" looks a bit weird, but I like the points brought up about
> avoiding to name a one-use variable (e.g., getArgs >>= case of ...)
> AFACS, this isn't easily implemented in Haskell either.

Erlang manages fine with multiclause 'fun':

(fun (1) -> "One" ; (_) -> "Not-one" end)(1)

ML manages fine with multiclause 'fn':

(fn 1 => "one" | _ => "not-one")(1)

In both cases, the same notation is used for multiclause lambda as
for single clause lambda. It seems excessively ugly to use
completely different notation depending on the number of alternatives,
especially when one of the notations has another, much more common,
and distinct usage.

Donn Cave

unread,
Oct 4, 2010, 7:49:57 PM10/4/10
to Richard O'Keefe, haskell-cafe
Quoth "Richard O'Keefe" <o...@cs.otago.ac.nz>,
...

> Erlang manages fine with multiclause 'fun':
>
> (fun (1) -> "One" ; (_) -> "Not-one" end)(1)
>
> ML manages fine with multiclause 'fn':
>
> (fn 1 => "one" | _ => "not-one")(1)
>
> In both cases, the same notation is used for multiclause lambda as
> for single clause lambda. It seems excessively ugly to use
> completely different notation depending on the number of alternatives,
> especially when one of the notations has another, much more common,
> and distinct usage.

Just to be sure, are you saying, rather than

case of
1 -> f
2 -> g

you'd like to see \ support pattern matching etc. like named functions -

\ 1 -> f
2 -> g

?
Donn

Richard O'Keefe

unread,
Oct 4, 2010, 8:35:51 PM10/4/10
to haskell-cafe cafe

On 5/10/2010, at 12:49 PM, Donn Cave wrote:
> Just to be sure, are you saying, rather than
>
> case of
> 1 -> f
> 2 -> g
>
> you'd like to see \ support pattern matching etc. like named functions -
>
> \ 1 -> f
> 2 -> g

Absolutely. For the record, lambda DOES support pattern matching
(Haskell 2010 report, section 3.3
lexp -> \ apat1 ... apatn -> exp
Lambda abstractions are written \ p1 ... pn -> e where
the pi are _patterns_.
)

To repeat, the analogues in SML and Erlang *do* support multiple
clauses (as well as pattern matching) and the failure of Haskell
lambdas to do so has always seemed like a weird restriction in a
language that's usually free of weird restrictions.

'case of' is terminally cute. I dare say its inventor felt
extremely proud of hacking it in, but it's the kind of thing
that will have admirers swearing in frustration when they get
tripped up by it yet again, and detractors sniggering.

I'd prefer to see something like
\ 1 -> f
| 2 -> g
but I'm sure something could be worked out.

Dean Herington

unread,
Oct 4, 2010, 11:04:04 PM10/4/10
to chri...@googlemail.com, Bulat Ziganshin, haskell-cafe
At 12:05 PM +0200 10/4/10, Christopher Done wrote:
>On 4 October 2010 10:55, Bulat Ziganshin <bulat.z...@gmail.com> wrote:
>> Hello Ketil,
>>
>> Monday, October 4, 2010, 11:30:48 AM, you wrote:
>>>> Prelude> (if then "Haskell" else "Cafe") False
>>
>> lambda-if is easily implemented in terms of usual functions.
>> and we even have one named bool:
>>
>> bool: Bool -> a -> a -> a
>
>I agree, in fact I have bool here:
>http://hackage.haskell.org/packages/archive/higherorder/0.0/doc/html/Data-Bool-Higher.html
>
>And the corresponding other types:
>
>bool :: (a -> b) -> (a -> b) -> (a -> Bool) -> a -> b
>list :: b -> ([a] -> b) -> [a] -> b
>maybe :: b -> (a -> b) -> Maybe a -> b
>
>But the case is especially useful for pattern matching.

I agree with others that lambda-if is better provided as a normal
function rather than special syntax, that lambda-case is much more
useful, and that it would be best if lambda-case were simply a
generalization of anonymous lambdas (\ ...).

With respect to "datatype destructing" functions, the Prelude has:

maybe :: b -> (a -> b) -> Maybe a -> b

either :: (a -> c) -> (b -> c) -> Either a b -> c

which suggests the following signatures for the analogues for Bool
and list types:

bool :: a -> a -> Bool -> a
list :: b -> (a -> [a] -> b) -> [a] -> b

(However, I do rather like the name (??) from Data.Bool.Higher, which
is used for "bool" immediately above. And I would hesitate to use
the name "list" for list destruction rather than construction. So
I'm not about to propose adding these two functions.)

Dean

Nicolas Wu

unread,
Oct 5, 2010, 2:52:10 AM10/5/10
to Richard O'Keefe, haskell-cafe cafe
> To repeat, the analogues in SML and Erlang *do* support multiple
> clauses (as well as pattern matching) and the failure of Haskell
> lambdas to do so has always seemed like a weird restriction in a
> language that's usually free of weird restrictions.

I agree with this sentiment. I have never understood why lambdas can't
handle multiple clauses.

> I'd prefer to see something like
>        \ 1 -> f
>        | 2 -> g
> but I'm sure something could be worked out.

This sounds sensible, since the lambda-case clause should really be
about having a lambda with support for cases, not a case statement
that's implicitly surrounded by a lambda. While I think the "case of"
is a good idea, multiple clauses in lambdas seems more canonical to
me.

Nick

Luke Palmer

unread,
Oct 5, 2010, 5:36:12 AM10/5/10
to Dean Herington, Bulat Ziganshin, haskell-cafe
On Mon, Oct 4, 2010 at 9:04 PM, Dean Herington
<heringt...@mindspring.com> wrote:
> With respect to "datatype destructing" functions, the Prelude has:
>
> maybe :: b -> (a -> b) -> Maybe a -> b
> either :: (a -> c) -> (b -> c) -> Either a b -> c
>
> which suggests the following signatures for the analogues for Bool and list
> types:
>
> bool :: a -> a -> Bool -> a
> list :: b -> (a -> [a] -> b) -> [a] -> b

This suggestion is not so clear to me. Maybe and Either are both
non-recursive, so the Church and Scott encodings coincide. You've
written the Scott encoding of list. The Church encoding should look
familiar:

list :: b -> (a -> b -> b) -> [a] -> b

Intuitively, a Scott encoding peels off one layer of datatype, whereas
a Church encoding flattens down a whole recursive structure. Church
encodings are more powerful -- you can do more without requiring a
fixed point operator.

Just to be clear, I am not arguing anything other than "maybe" and
"either" don't readily generalize to "list" because of list's
recursiveness.

Luke

Neil Brown

unread,
Oct 5, 2010, 7:30:23 AM10/5/10
to haskell-cafe cafe
On 05/10/10 07:52, Nicolas Wu wrote:
>> I'd prefer to see something like
>> \ 1 -> f
>> | 2 -> g
>> but I'm sure something could be worked out.
>>
> While I think the "case of"
> is a good idea, multiple clauses in lambdas seems more canonical to
> me.
>

Alternatively, we could abandon lambdas and just use lambda-case.

All expressions like \1 -> f become case of 1 -> f

Multi-argument functions are a bit more verbose, as we effectively go
back to single argument functions with manual currying:

\x (C y) -> z becomes: case of {x -> case of {C y -> z}}

There is the small matter of losing backwards compatibility, of course.
But on the plus side, this would reduce the number of constructions in
the language by one. (I think the strictness semantics, etc match up
for this transformation?).

;-)

Thanks,

Neil.

Nicolas Pouillard

unread,
Oct 5, 2010, 8:58:19 AM10/5/10
to Luke Palmer, Dean Herington, Bulat Ziganshin, haskell-cafe
On Tue, 5 Oct 2010 03:36:12 -0600, Luke Palmer <lrpa...@gmail.com> wrote:
> On Mon, Oct 4, 2010 at 9:04 PM, Dean Herington
> <heringt...@mindspring.com> wrote:
> > With respect to "datatype destructing" functions, the Prelude has:
> >
> > maybe :: b -> (a -> b) -> Maybe a -> b
> > either :: (a -> c) -> (b -> c) -> Either a b -> c
> >
> > which suggests the following signatures for the analogues for Bool and list
> > types:
> >
> > bool :: a -> a -> Bool -> a
> > list :: b -> (a -> [a] -> b) -> [a] -> b
>
> This suggestion is not so clear to me. Maybe and Either are both
> non-recursive, so the Church and Scott encodings coincide. You've
> written the Scott encoding of list. The Church encoding should look
> familiar:
>
> list :: b -> (a -> b -> b) -> [a] -> b

I would argue for the previous one (Scott), since we already have this one
(this is foldr with another order for arguments).

--
Nicolas Pouillard
http://nicolaspouillard.fr

Gábor Lehel

unread,
Oct 5, 2010, 11:32:33 AM10/5/10
to haskell-cafe cafe
I also vote +1 for lambda-case, and abstain for lambda-if.

I don't think multiple-clause lambdas being desirable should be an
argument against lambda-case. After all, we can also define top-level
functions with either multiple clauses or a single case expression.
Haskell has always followed the TMTOWTDI school of thought with
regards to syntax, as far as I know. And lambda-case has the notable
advantage that someone has gone and implemented it.

Ozgur Akgun

unread,
Oct 5, 2010, 11:39:30 AM10/5/10
to Max Bolingbroke, haskell-cafe
For what it's worth, after all this discussion my rather cheeky preference is as follows:

Instead of introducing more specialised syntax, remove both existing special syntaxes for if and case, and introduce multi-clause support for lambdas!

Cheers!

On 2 October 2010 19:23, Max Bolingbroke <batters...@hotmail.com> wrote:
Hi Cafe,

I implemented the proposed Haskell' feature lambda-case/lambda-if [1]
during the Haskell Implementors Workshop yesterday for a bit of fun.
The patches are online [2, 3].

The feature is demonstrated in this GHCi session:

$ inplace/bin/ghc-stage2 --interactive -XLambdaCase
GHCi, version 7.1.20101002: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> (if then "Haskell" else "Cafe") False
"Cafe"

Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
"One"
Prelude> :q

Do you like this feature and think it would be worth incorporating
this into GHC? Or is it too specialised to be of use? If there is
enough support, I'll create a ticket and see what GHC HQ make of it.

Max

[1] http://hackage.haskell.org/trac/haskell-prime/ticket/41
[2] http://www.omega-prime.co.uk/files/LambdaCase-Testsuite.patch
[3] http://www.omega-prime.co.uk/files/LambdaCase-Compiler.patch
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



--
Ozgur Akgun

Henning Thielemann

unread,
Oct 5, 2010, 12:38:11 PM10/5/10
to Richard O'Keefe, haskell-cafe cafe
Richard O'Keefe schrieb:

> I'd prefer to see something like
> \ 1 -> f
> | 2 -> g
> but I'm sure something could be worked out.

In order to be consistent with current case, maybe in layout mode:

\1 -> f
2 -> g

and in non-layout mode

\{1 -> f; 2 -> g}

?

Brandon S Allbery KF8NH

unread,
Oct 5, 2010, 12:56:50 PM10/5/10
to haskel...@haskell.org
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 10/5/10 12:38 , Henning Thielemann wrote:
> In order to be consistent with current case, maybe in layout mode:
>
> \1 -> f
> 2 -> g
>
> and in non-layout mode
>
> \{1 -> f; 2 -> g}

+1; likewise for consistency it should support guards (which would preclude
using | the way Richard suggested, and goes along with the "lambda-case" thing).

- --
brandon s. allbery [linux,solaris,freebsd,perl] all...@kf8nh.com
system administrator [openafs,heimdal,too many hats] all...@ece.cmu.edu
electrical and computer engineering, carnegie mellon university KF8NH
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.10 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkyrWNIACgkQIn7hlCsL25WPLwCfYGc4KUscdpv3lJ7lQbugtbIa
jz4An2mbZdJr3LZY6rF0qZjBcle4HLsX
=kR9R
-----END PGP SIGNATURE-----

Ketil Malde

unread,
Oct 5, 2010, 3:28:25 PM10/5/10
to Donn Cave, haskell-cafe
Donn Cave <do...@avvanta.com> writes:

> I think you're not the first to ask. Just out of curiosity, or is
> there a use for these variations?

Just that they seem to be natural generalizations. If it's just the
single form of paramtrizing the condition, I think it's better served by
a regular function, 'bool' or (??) or whatever.

> The reason for the initially proposed construct seems clear enough
> to me, it's very much like `case'.

> getargs >>= if then beTrue else beFalse . (==) ["-t"]

Isn't this equivalent, and only slightly more cumbersome?

getArgs >>= case of {True -> beTrue; False -> beFalse} . (==) ["-t"]

(And of course,

getArgs >>= case of ["-t"] -> beTrue; _ -> beFalse

is probably clearer anyway.)

-k
--
If I haven't seen further, it is by standing in the footprints of giants

Donn Cave

unread,
Oct 5, 2010, 5:25:44 PM10/5/10
to haskell-cafe
Quoth Ketil Malde <ke...@malde.org>,
...

> Just that they seem to be natural generalizations. If it's just the
> single form of paramtrizing the condition, I think it's better served by
> a regular function, 'bool' or (??) or whatever.

Well, yes, there's some logic to that. Like,

bool b c a = if a
then b
else c

getArgs >>= bool (putStrLn "long") (putStrLn "short") . (> 0) . length

And I agree that's competitive with lambda-if as I understand it -
though possibly not for the same reasons.

For me, Haskell is not Lisp. Haskell's syntax takes a different direction,
a mix of S-expression with stuff like if-then-else, and it works. If the
lambda-if feature is actually useful in a way that takes advantage of
the strength of the if-then-else notation, then I'm all for it.

The problem is that due to the rarity of True/False as ... terminal
value of a computation (I just made that up!), neither of these
constructs is going to be worth much. Forget about lambda-if, even
the regular function looks like hell -

bool (putStrLn "long") (putStrLn "short") . (> 0) . length

Compared to

\ t -> if length t > 0 then putStrLn "long" else putStrLn "short"

... and much more so, with less trivial examples.

In a brief survey of my own very small code base, I see only "hIsEOF"
as a place where I could really use lambda-if. There, it would be
vastly better than a regular bool function, but that's a pretty minimal
use case.

Donn

Max Bolingbroke

unread,
Oct 5, 2010, 7:04:10 PM10/5/10
to Henning Thielemann, haskell-cafe cafe
On 5 October 2010 17:38, Henning Thielemann

<schle...@henning-thielemann.de> wrote:
> Richard O'Keefe schrieb:
>
>> I'd prefer to see something like
>>       \ 1 -> f
>>       | 2 -> g
>> but I'm sure something could be worked out.
>
> In order to be consistent with current case, maybe in layout mode:
>
> \1 -> f
>  2 -> g
>
> and in non-layout mode
>
> \{1 -> f; 2 -> g}

Duncan Coutts also suggested this possibility to me - once I saw it
actually liked it rather better than the lambda-case stuff,
particularly since it generalises nicely to multiple arguments. I may
try to write a patch for this extension instead when I get some free
time.

To those asking where lambda-if comes from: it was just something I
hacked in while I was there - I don't have a particular motivation
example. It just seemed like a natural extension of the lambda-case
idea.

Cheers,
Max

Max Bolingbroke

unread,
Oct 5, 2010, 7:06:24 PM10/5/10
to Conal Elliott, haskell-cafe
On 4 October 2010 00:38, Conal Elliott <co...@conal.net> wrote:
> I like it!
>
> Are the other sections available as well, e.g.,
>
>     (if False then else "Cafe") "Haskell" --> "Cafe"

They are not, though this would certainly make sense for lambda-if.
It's not so clear with lambda-case because of the issue of free
variables. Potentially we could support something like this, but it's
a bit scary-looking:

(case x of Just -> ; Nothing ->) (\y -> "I'm a Just") "I'm a nothing"

Cheers,
Max

Richard O'Keefe

unread,
Oct 5, 2010, 8:02:21 PM10/5/10
to Brandon S Allbery KF8NH, haskel...@haskell.org

On 6/10/2010, at 5:56 AM, Brandon S Allbery KF8NH wrote:

>> In order to be consistent with current case, maybe in layout mode:
>>
>> \1 -> f
>> 2 -> g
>>
>> and in non-layout mode
>>
>> \{1 -> f; 2 -> g}
>
> +1; likewise for consistency it should support guards (which would preclude
> using | the way Richard suggested, and goes along with the "lambda-case" thing).

It's not that I particularly wanted "|".
Just that I thought some sort of visual mark would be a good idea.
Forget I ever suggested it.

Evan Laforge

unread,
Oct 5, 2010, 8:10:43 PM10/5/10
to Max Bolingbroke, Henning Thielemann, haskell-cafe cafe
-1 for if then. The examples of "curried" if then else look, to my
eyes, less readable than the pointed version. And it's easy enough to
write a 'bool' deconstructor, or an 'ifM' for the monadic case.

+1 for something to solve the "dummy <- m; case dummy of" problem.
Here are the possibilities I can think of:

1) case of:

m >>= case of
Just _ <- z | guard -> a
_ -> b

2) habit's case<-

case<- m of
Just _ <- z | guard -> a
_ -> b

3) extended lambda (not sure what this would look like... would the
below parse with the give layout?)

m >>= \
Just _ <- z | guard -> a
_ -> b

To me, #3 looks less ad-hoc and I like the idea of loosening a
restriction instead of introducing more sugar, but I'm not sure how
the syntax would work out. Also, from another point of view, 'f x =
...' is sugared to combine a \ and a case, while \ is unsugared, so
tacking some case sugar on to \ would introduce sugar in a previously
sugar-free area. Of course that \ is already sugared to curry
automatically, but if you rephrase this as "add more sugar" rather
than "loosen a restriction" it suddenly becomes less attractive since
now it's just sugar vs. sugar :)

#2 looks the nicest for this specific use, but seems less general than
#1. For instance, #1 allows "f = case of { ... } . g".

So I like #1.

Dean Herington & Elizabeth Lacey

unread,
Oct 6, 2010, 12:51:10 AM10/6/10
to Luke Palmer, haskell-cafe
At 3:36 AM -0600 10/5/10, Luke Palmer wrote:
>On Mon, Oct 4, 2010 at 9:04 PM, Dean Herington
><heringt...@mindspring.com> wrote:
>> With respect to "datatype destructing" functions, the Prelude has:
>>
>> maybe :: b -> (a -> b) -> Maybe a -> b
>> either :: (a -> c) -> (b -> c) -> Either a b -> c
>>
>> which suggests the following signatures for the analogues for Bool and list
>> types:
>>
>> bool :: a -> a -> Bool -> a
>> list :: b -> (a -> [a] -> b) -> [a] -> b
>
>This suggestion is not so clear to me. Maybe and Either are both
>non-recursive, so the Church and Scott encodings coincide. You've
>written the Scott encoding of list. The Church encoding should look
>familiar:
>
> list :: b -> (a -> b -> b) -> [a] -> b
>
>Intuitively, a Scott encoding peels off one layer of datatype, whereas
>a Church encoding flattens down a whole recursive structure. Church
>encodings are more powerful -- you can do more without requiring a
>fixed point operator.
>
>Just to be clear, I am not arguing anything other than "maybe" and
>"either" don't readily generalize to "list" because of list's
>recursiveness.
>
>Luke

Thanks, Luke, for pointing out the Church vs. Scott encoding issue.
I agree with your conclusion (and feel better about the lack of the
version of "list" I had suggested).

Dean

Simon Marlow

unread,
Oct 6, 2010, 5:39:37 AM10/6/10
to Max Bolingbroke, Henning Thielemann, haskell-cafe cafe
On 06/10/2010 00:04, Max Bolingbroke wrote:
> On 5 October 2010 17:38, Henning Thielemann
> <schle...@henning-thielemann.de> wrote:
>> Richard O'Keefe schrieb:
>>
>>> I'd prefer to see something like
>>> \ 1 -> f
>>> | 2 -> g
>>> but I'm sure something could be worked out.
>>
>> In order to be consistent with current case, maybe in layout mode:
>>
>> \1 -> f
>> 2 -> g
>>
>> and in non-layout mode
>>
>> \{1 -> f; 2 -> g}
>
> Duncan Coutts also suggested this possibility to me - once I saw it
> actually liked it rather better than the lambda-case stuff,
> particularly since it generalises nicely to multiple arguments. I may
> try to write a patch for this extension instead when I get some free
> time.

A slightly different suggestion from Simon PJ and myself (we agreed on
something syntax-related :-) is the following:

\case 1 -> f
2 -> g

where the two-token sequence '\ case' introduces a new optional layout
context, the body of which is exactly the same as in a case expression.
So you could also write

\case { 1 -> f; 2 -> g }

if you want. Guards are allowed of course.

The motivation for this syntax is:

* easy to mentally parse: \ still introduces a function.
(better than 'case of' in this respect)

* a bit more noisy than just \: I'm not sure what the
ramifications of having \ introduce a layout context
on its own would be, but I suspect there would be difficulties.
Certainly some existing code would fail to parse, e.g.

(case e of [] -> \x -> x+1; (x:xs) -> \x -> x+2)


Cheers,
Simon

Matthew Gruen

unread,
Oct 6, 2010, 11:45:57 AM10/6/10
to chri...@googlemail.com, haskell-cafe
On 10/2/10, Christopher Done <chri...@googlemail.com> wrote:

> On 2 October 2010 20:23, Max Bolingbroke <batters...@hotmail.com> wrote:
>> Do you like this feature and think it would be worth incorporating
>> this into GHC? Or is it too specialised to be of use? If there is
>> enough support, I'll create a ticket and see what GHC HQ make of it.
>
> Nice work! I like it and have wanted it for a while, and I know many
> in the #haskell IRC channel would like it. The case is especially
> useful. Maybe the if is only useful sometimes.
>
+1 for `case of'... I have called for it on many an occasion in
#haskell. Thanks for implementing it, Max!

I primarily see it as a way to remove a point from `\x -> case x of
...', not a way to augment lambdas with pattern matching, like in `\0
-> 1 \n k -> k-1'. I suppose both of them work with monadic casing,
with the `m >>=' trick. `\case' or `\case of' would work okay as well,
the former Simon suggested, but some keywords *somewhere* would be
nice, to avoid a perl-like procession of punctuation. (But the code
golfer in me says otherwise.)

Matt

Christopher Done

unread,
Oct 6, 2010, 12:02:44 PM10/6/10
to Simon Marlow, Henning Thielemann, haskell-cafe cafe
On 6 October 2010 11:39, Simon Marlow <marl...@gmail.com> wrote:
>   Certainly some existing code would fail to parse, e.g.
>   (case e of [] -> \x -> x+1; (x:xs) -> \x -> x+2)

That's definitely a problem. The multi-pattern lambda is nice as I
think it follows naturally from function definitions (indeed, I think
many a Haskeller including myself have written (\x -> k; \y -> l) once
expecting it to work), but problems like this are kind of a deal
breaker.

> A slightly different suggestion from Simon PJ and myself (we agreed on
> something syntax-related :-) is the following:
>
>  \case 1 -> f
>        2 -> g

> ...


>  \case { 1 -> f; 2 -> g }
>

+1

I like this because it has exactly the same properties of Max's
case-of, but is shorter and still reads with sense.

I created a poll about for/against the case-of idea, but it seems,
just from the messages here, unanimous that people *do* want something
like this, mostly to solve the unnecessary/dummy formal parameters
problem.

steffen

unread,
Oct 6, 2010, 4:32:32 PM10/6/10
to haskel...@haskell.org
> > A slightly different suggestion from Simon PJ and myself (we agreed on
> > something syntax-related :-) is the following:
>
> >  \case 1 -> f
> >        2 -> g
> > ...
> >  \case { 1 -> f; 2 -> g }
>
> +1
>
> I like this because it has exactly the same properties of Max's
> case-of, but is shorter and still reads with sense.
+1

Gregory Crosswhite

unread,
Oct 6, 2010, 4:36:56 PM10/6/10
to haskel...@haskell.org
+1...million

Cheers,
Greg

Sterling Clover

unread,
Oct 6, 2010, 4:43:47 PM10/6/10
to Simon Marlow, Henning Thielemann, haskell-cafe cafe

On Oct 6, 2010, at 5:39 AM, Simon Marlow wrote:

> A slightly different suggestion from Simon PJ and myself (we agreed on something syntax-related :-) is the following:
>
> \case 1 -> f
> 2 -> g
>
> where the two-token sequence '\ case' introduces a new optional layout context, the body of which is exactly the same as in a case expression. So you could also write
>
> \case { 1 -> f; 2 -> g }
>
> if you want. Guards are allowed of course.

> * a bit more noisy than just \: I'm not sure what the


> ramifications of having \ introduce a layout context
> on its own would be, but I suspect there would be difficulties.
> Certainly some existing code would fail to parse, e.g.
>
> (case e of [] -> \x -> x+1; (x:xs) -> \x -> x+2)

\ introducing a layout context is a no-go because, as in the example given, it breaks too much code. However, \case as described is somewhat less powerful. In particular, \ with a layout context lets us have multi-argument pattern matching, while both \case and "case of" give only single argument pattern matching. I don't know if the extra functionality is that important, but I don't see why we can't provide for it anyway, as in:

\case (x:xs) n -> go xs; _ n -> n;

Cheers,
Sterl._______________________________________________

Dean Herington

unread,
Oct 6, 2010, 7:45:42 PM10/6/10
to Sterling Clover, Simon Marlow, haskell-cafe cafe

I would also very much like to have multi-argument pattern matching, but in

\case a b -> ...
...

it sure suggests to me that `a` should be applied to `b` before casing.

Dean

Evan Laforge

unread,
Oct 6, 2010, 8:34:18 PM10/6/10
to Dean Herington, Simon Marlow, haskell-cafe cafe
> I would also very much like to have multi-argument pattern matching, but in
>
>    \case a b -> ...
>          ...
>
> it sure suggests to me that `a` should be applied to `b` before casing.

I feel like sugar is designed to make a couple of specific uses nicer.
Being as general and orthogonal as possible is the job of the
primitives. So I don't mind too much if sugar is a little ad-hoc.
Single argument \case addresses the monadic case problem. Does
someone have some examples of nice expressions that you need a multi
argument case-lambda for?

I don't mind writing 'case (a, b) of ...' very much. Seems like you
could get the same effect with 'curry':

(\case { a b -> ... ; a b -> ...}) x y

can be written

(curry $ \case { (a, b) -> ... }) x y

Not as pretty, but still point-free.

Jean-Marie Gaillourdet

unread,
Oct 7, 2010, 10:34:32 AM10/7/10
to Sterling Clover, haskel...@haskell.org
Hi,

On 06.10.2010, at 22:43, Sterling Clover wrote:

>
> On Oct 6, 2010, at 5:39 AM, Simon Marlow wrote:
>
>> A slightly different suggestion from Simon PJ and myself (we agreed on something syntax-related :-) is the following:
>>
>> \case 1 -> f
>> 2 -> g
>>
>> where the two-token sequence '\ case' introduces a new optional layout context, the body of which is exactly the same as in a case expression. So you could also write
>>
>> \case { 1 -> f; 2 -> g }
>>
>> if you want. Guards are allowed of course.
>
>> * a bit more noisy than just \: I'm not sure what the
>> ramifications of having \ introduce a layout context
>> on its own would be, but I suspect there would be difficulties.
>> Certainly some existing code would fail to parse, e.g.
>>
>> (case e of [] -> \x -> x+1; (x:xs) -> \x -> x+2)
>
> \ introducing a layout context is a no-go because, as in the example given, it breaks too much code. However, \case as described is somewhat less powerful. In particular, \ with a layout context lets us have multi-argument pattern matching, while both \case and "case of" give only single argument pattern matching. I don't know if the extra functionality is that important, but I don't see why we can't provide for it anyway, as in:
>
> \case (x:xs) n -> go xs; _ n -> n;

Then, there is an inconsistency between lambda-case and traditional case and people will start complaining about that.

Haskell98 is a very well thought out language with very few syntactiv warts. I'd avoid introducing new language extensions which do introduce new warts. Backwards compatibility is not so important, because GHC will hopefully make it optional. Even when an extended \{ p1 -> e1; p2 -> e2 } is part of Haskell 2012 GHC will probably support Haskell 2011 as well. Therefore, I'd worry less about backwards compatibility, but concentrate more on consistency and elegance. I.e I'll favor
\p1 p2 -> e1
p3 p4 -> e2

Just my 2 cents.

-- Jean_______________________________________________

Peter Wortmann

unread,
Oct 7, 2010, 1:03:48 PM10/7/10
to haskel...@haskell.org

On Tue, 2010-10-05 at 17:10 -0700, Evan Laforge wrote:
> +1 for something to solve the "dummy <- m; case dummy of" problem.
> Here are the possibilities I can think of:

Might be off-topic here, but I have wondered for a while why Haskell
doesn't support something like follows:

do case (<- m) of ...

With the more general rule being:

do ... e (<- m) g
=>
... m >>= \tmp -> e tmp g

Reasons:
* "<-" is already "sugary", and the transformation is similar. Just
removes the need for the user to define a throw-away name.
* Better than liftMX and the Applicative operators. As shown, this is
more flexible while requiring less magic operators as a bonus. Also
makes more clear where the sides effects actually are.
* Goes well with the spirit of getting the good parts of imperative
coding where it potentially makes the code more concise. Can be
abused, obviously, but I have also seen a lot of code that I feel
could be written better using this.

Anything I am overlooking here? I tried to find a discussion about
something like this, but didn't really know what to look for...

Greetings,
Peter Wortmann

Miguel Mitrofanov

unread,
Oct 7, 2010, 1:36:53 PM10/7/10
to Peter Wortmann, haskel...@haskell.org

О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫ iPhone

Oct 7, 2010, О©╫ 21:03, Peter Wortmann <sc...@leeds.ac.uk> О©╫О©╫О©╫О©╫О©╫О©╫О©╫(О©╫):

>
> On Tue, 2010-10-05 at 17:10 -0700, Evan Laforge wrote:
>> +1 for something to solve the "dummy <- m; case dummy of" problem.
>> Here are the possibilities I can think of:
>
> Might be off-topic here, but I have wondered for a while why Haskell
> doesn't support something like follows:
>
> do case (<- m) of ...

I think it'd be better to write just 'case (<- m) of', without 'do'.

Nicolas Pouillard

unread,
Oct 7, 2010, 5:45:58 PM10/7/10
to Peter Wortmann, haskel...@haskell.org
On Thu, 07 Oct 2010 18:03:48 +0100, Peter Wortmann <sc...@leeds.ac.uk> wrote:
>
> On Tue, 2010-10-05 at 17:10 -0700, Evan Laforge wrote:
> > +1 for something to solve the "dummy <- m; case dummy of" problem.
> > Here are the possibilities I can think of:
>
> Might be off-topic here, but I have wondered for a while why Haskell
> doesn't support something like follows:
>
> do case (<- m) of ...
>
> With the more general rule being:
>
> do ... e (<- m) g
> =>
> ... m >>= \tmp -> e tmp g
>
> Reasons:
> * "<-" is already "sugary", and the transformation is similar. Just
> removes the need for the user to define a throw-away name.
> * Better than liftMX and the Applicative operators. As shown, this is
> more flexible while requiring less magic operators as a bonus. Also
> makes more clear where the sides effects actually are.
> * Goes well with the spirit of getting the good parts of imperative
> coding where it potentially makes the code more concise. Can be
> abused, obviously, but I have also seen a lot of code that I feel
> could be written better using this.
>
> Anything I am overlooking here? I tried to find a discussion about
> something like this, but didn't really know what to look for...

Your notation feels very tempting, however it relies a lot on finding
the "do" to put the bind. Recall that "do" is just syntax, and that
it has no more meaning than its desugaring.

Imagine these examples:

do {a; b (<- c) d; e} => do {a; x <- c; b x d; e}

do {a >> b (<- c) d; e}
|
+--> do {x <- c; a >> b x d; e}
|
+--> do {a; x <- c; b x d; e}

Imagine that "b" can be equal to "b1 >> b2" and so where placing the
"x <- c" is non obvious and it should be.

On the other hand case (<- m) of {...} being translated into
m >>= \x -> case x of {...} is non-ambigous.

Best regards,

--
Nicolas Pouillard
http://nicolaspouillard.fr

Lauri Alanko

unread,
Oct 7, 2010, 6:13:20 PM10/7/10
to haskel...@haskell.org
On Thu, Oct 07, 2010 at 02:45:58PM -0700, Nicolas Pouillard wrote:
> On Thu, 07 Oct 2010 18:03:48 +0100, Peter Wortmann <sc...@leeds.ac.uk> wrote:
> > Might be off-topic here, but I have wondered for a while why Haskell
> > doesn't support something like follows:
> >
> > do case (<- m) of ...
> >
> > With the more general rule being:
> >
> > do ... e (<- m) g
> > =>
> > ... m >>= \tmp -> e tmp g

Your "general" rule doesn't subsume your case example, since a case
expression is not an application. I think you mean something like

do C[(<- m)]
=>
m >>= \tmp -> C[tmp]

where C is an arbitrary expression context. It could further be
generalized to allow several (<- ...) subterms in an expression, with
implied left-to right sequencing. Frankly, that seems like a very
attractive way to make the do-notation into a more practical
imperative sub-language.

This should probably also cover binding, i.e. do { p <- C[(<- m)];
... } should also work.

> Imagine these examples:
>
> do {a; b (<- c) d; e} => do {a; x <- c; b x d; e}
>
> do {a >> b (<- c) d; e}
> |
> +--> do {x <- c; a >> b x d; e}
> |
> +--> do {a; x <- c; b x d; e}

To my understanding no rule would produce this latter variant. do {a;
b} is transformed into a >> do {b}, not the other way around. The
proposed transformation rule seems clear to me: the context covers the
entire expression-statement, including of course expressions
containing monadic operations:

do {a >> b (<- c) d; e} => c >>= \x -> a >> b x d >> e

and if you want a to go before c, you have to do

do {a; b (<- c) d; e) => a >> c >>= \x -> b x d >> e

> Imagine that "b" can be equal to "b1 >> b2" and so where placing the
> "x <- c" is non obvious and it should be.

I don't see what this has to do with anything. All we are interested
in is the syntax of do-expressions. The do-transformation is
completely oblivious to monadic operations within the statements, it
only produces some more monadic operations.

Cheers,


Lauri

Nicolas Pouillard

unread,
Oct 8, 2010, 8:41:25 AM10/8/10
to Lauri Alanko, haskel...@haskell.org
On Fri, 8 Oct 2010 01:13:20 +0300, Lauri Alanko <l...@iki.fi> wrote:
> On Thu, Oct 07, 2010 at 02:45:58PM -0700, Nicolas Pouillard wrote:
> > On Thu, 07 Oct 2010 18:03:48 +0100, Peter Wortmann <sc...@leeds.ac.uk> wrote:
> > > Might be off-topic here, but I have wondered for a while why Haskell
> > > doesn't support something like follows:
> > >
> > > do case (<- m) of ...
> > >
> > > With the more general rule being:
> > >
> > > do ... e (<- m) g
> > > =>
> > > ... m >>= \tmp -> e tmp g
>
> Your "general" rule doesn't subsume your case example, since a case
> expression is not an application. I think you mean something like
>
> do C[(<- m)]
> =>
> m >>= \tmp -> C[tmp]
>
> where C is an arbitrary expression context. It could further be
> generalized to allow several (<- ...) subterms in an expression, with
> implied left-to right sequencing. Frankly, that seems like a very
> attractive way to make the do-notation into a more practical
> imperative sub-language.

This is clearer. However this does not seems very robust against manual
refactoring of the "do" notation.

Imagine find this code:

do s1
C[(<- s2)]

And I don't see the (<- s2) in C, and so I refactor it as:

s1 >> C[(<- s2)]

And so the s2 get affected somewhere else.

--
Nicolas Pouillard
http://nicolaspouillard.fr

Peter Wortmann

unread,
Oct 8, 2010, 10:09:21 AM10/8/10
to haskel...@haskell.org

On Fri, 2010-10-08 at 01:13 +0300, Lauri Alanko wrote:
> Your "general" rule doesn't subsume your case example, since a case
> expression is not an application. I think you mean something like
>
> do C[(<- m)]
> =>
> m >>= \tmp -> C[tmp]
>
> where C is an arbitrary expression context. It could further be
> generalized to allow several (<- ...) subterms in an expression, with
> implied left-to right sequencing.

Yes, that's what I meant. Thanks for describing it properly.

On Fri, 2010-10-08 at 05:41 -0700, Nicolas Pouillard wrote:
> Imagine find this code:
>
> do s1
> C[(<- s2)]
>
> And I don't see the (<- s2) in C, and so I refactor it as:
>
> s1 >> C[(<- s2)]

This is roughly what I meant with "abused": Where "C" is very complex,
it might become non-obvious where exactly the monad actions are supposed
to happen. Hence such traps when refactoring.

Also of note: Just moving sub-expressions around isn't something that is
guaranteed to be save. Introducing new names and using them in "s2"
would be problematic, for example:

do map (\x -> (<- putStrLn x)) ["a", "b"]

Obviously can't be made to work. You might have to check for this - or
maybe even disallow the shorthand inside lamdbas and lets. Might be less
satisfying to have such special cases, but it is still a good bit more
general than what is available right now.

Greetings,
Peter Wortmann

Jonathan Geddes

unread,
Oct 8, 2010, 12:34:13 PM10/8/10
to Peter Wortmann, haskel...@haskell.org

I can honestly say that I haven't felt much pain from the status quo regarding this. Most of the time my code is structured so that case statements don't appear in do blocks. When they do, I don't see it as a big issue. The special case for operator - is a bigger wart on haskell syntax than this, imo.

I would vote in favor of keeping the language simple. I do like the idea of generalizing lambda functions to include multiple cases, however.

On the other hand, I almost never use lambdas now since named functions yield better "self-documenting" code.

--jonathan

On Oct 8, 2010 8:09 AM, "Peter Wortmann" <sc...@leeds.ac.uk> wrote:


On Fri, 2010-10-08 at 01:13 +0300, Lauri Alanko wrote:

> Your "general" rule doesn't subsume your ...

Yes, that's what I meant. Thanks for describing it properly.


On Fri, 2010-10-08 at 05:41 -0700, Nicolas Pouillard wrote:
> Imagine find this code:
>
> do s1

> ...

This is roughly what I meant with "abused": Where "C" is very complex,
it might become non-obvious where exactly the monad actions are supposed
to happen. Hence such traps when refactoring.

Also of note: Just moving sub-expressions around isn't something that is
guaranteed to be save. Introducing new names and using them in "s2"
would be problematic, for example:

 do map (\x -> (<- putStrLn x)) ["a", "b"]

Obviously can't be made to work. You might have to check for this - or
maybe even disallow the shorthand inside lamdbas and lets. Might be less
satisfying to have such special cases, but it is still a good bit more
general than what is available right now.

Greetings,
 Peter Wortmann



_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org...

Reply all
Reply to author
Forward
0 new messages