Opened 5 years ago

Last modified 3 years ago

#4359 closed feature request

Implement lambda-case/lambda-if — at Version 68

Reported by: batterseapower Owned by:
Priority: high Milestone: 7.6.1
Component: Compiler Version: 7.1
Keywords: Cc: hydo@…, cmoore@…, hackage.haskell.org@…, uzytkownik2@…, leather@…, illissius@…, mikhail.vorozhtsov@…, anton.nik@…, dterei, g9ks157k@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Revisions:

Description (last modified by simonpj)

I put together a patch for this Haskell' proposal (http://hackage.haskell.org/trac/haskell-prime/ticket/41)

    Prelude> (if then "Haskell" else "Cafe") False
    "Cafe"
    Prelude> (case of 1 -> "One"; _ -> "Not-one") 1
    "One"

There seems to be some support for integrating this proposal into GHC (see http://permalink.gmane.org/gmane.comp.lang.haskell.cafe/81366)

The attached patches implement the feature, test it and document it.

See also the wiki page LambdasVsPatternMatching.

Change History (72)

Changed 5 years ago by batterseapower

Changed 5 years ago by batterseapower

comment:1 Changed 5 years ago by igloo

The motivating examples seem to be of the form

getArgs >>= case of
            [] -> error "No args"
            fs -> doit fs

so I wonder if a better extension would be:

mcase getArgs of
[] -> error "No args"
fs -> doit fs

comment:2 follow-up: Changed 5 years ago by malcolm.wallace@…

I would disagree that monadic bindings are the only (or even a major) use case.
Personally, I would often like the ability to have a standard lambda that can discriminate patterns on the value being bound.

foo = map (case of Alt1 a -> burble a
                   Alt2 | (x:xs) <- something    -> something more
                   otherwise -> def)

Lambda-case is more general than mcase.

comment:3 Changed 5 years ago by simonmar

+1 for lambda-case and lambda-if.

In a similar vein, I'd like to have multi-way if:

case | x < y     -> ...
     | x == y    -> ...
     | otherwise -> ...

comment:4 follow-up: Changed 5 years ago by simonmar

hmm, on second thoughts I revise that to +0 for lambda-case and lambda-if. They save a constant number of tokens (4), but the downside is that we have to adjust our mental parsers/typecheckers to recognise if then and case of as a lambda, and I'm not sure the gain in brevity is worth the loss of readability. (note that multi-way if doesn't suffer from this problem, it's just an abbreviation).

comment:5 in reply to: ↑ 2 Changed 5 years ago by igloo

Replying to malcolm.wallace@…:

I would disagree that monadic bindings are the only (or even a major) use case.

By "The motivating examples" I meant "The motivating examples in the thread linked to".

Personally, I would often like the ability to have a standard lambda that can discriminate patterns on the value being bound.

Do you have any realworld examples, OOI?

From a style point of view, using it point-free, as in your example, I think looks OK, but if it was being applied to something non-trivial (or even being composed with something non-trivial) I think it would be clearer if written using a let-bound function.

comment:6 Changed 5 years ago by hydo

  • Cc hydo@… added

comment:7 Changed 5 years ago by hydo

  • Cc cmoore@… added

comment:8 in reply to: ↑ 4 Changed 5 years ago by isaacdupree

Replying to simonmar:

hmm, on second thoughts I revise that to +0 for lambda-case and lambda-if. They save a constant number of tokens (4), but the downside is that we have to adjust our mental parsers/typecheckers to recognise if then and case of as a lambda, and I'm not sure the gain in brevity is worth the loss of readability. (note that multi-way if doesn't suffer from this problem, it's just an abbreviation).

"They save a constant number of tokens (4)" -- this is true, but the overhead is a bit more than just the tokens "\" "x" "->" (case) "x" (of ...). There's the mental complication of that name "x". You need to think, reading it: Is 'x' used anywhere later under the case/lambda?(no). And writing it: Are there variables named 'x' that we're accidentally shadowing, or otherwise using the same name confusingly?

I'm open to other suggestions than lambda-case/lambda-if that would help this mental-overhead issue.

comment:9 Changed 5 years ago by simonpj

  • Description modified (diff)

comment:10 Changed 5 years ago by simonpj

There is a lot of traffic about this on Haskell Cafe http://www.mail-archive.com/[email protected]/index.html#82264. There seems to be enthusiasm, but also plenty of discussion of variants and alternatives.

My own gut feel is that it's a lot better to have an initial symbol to say "here comes a function". So I'm keener on the multi-clause lambda idea, if someone can devise a syntax that works. GHC's internals assume a multi-clause lambda anyway, so it's more or less just a syntactic issue.

Simon

comment:11 Changed 5 years ago by simonpj

Chatting to Simon we came up with this syntax:

  \case { blah }  ==>   \x -> case x of { blah }

Things to note:

  • No syntactic collision: at the moment a lambda cannot be followed by the keyword case.
  • The form (a) denotes a function, and (b) starts with a lambda. That's consistent with Haskell today.
  • The \case would be a "layout herald" (ie starts a laid-out block), just as of is now. (A variant would be to use \of instead of \case; then of is the layout herald in both cases.)
  • The syntax of { blah } is precisely that of a case expression, guards and all. Nothing new to explain.

I rather like this. I can't think why we didn't think of it before.

Simon

comment:12 Changed 5 years ago by igloo

\ of is my favourite of the lambda-case syntaxes, although I still think mcase would provide more benefit (no reason we can't have both, though).

comment:13 Changed 5 years ago by batterseapower

Another variant would be something like this:

\case { (Just x) (Just y) -> x + y; _ _ -> 1 }  ==> \a b -> case (a, b) of { (Just x, Just y) -> x +y; (_, _) -> 1 }

This syntax would give us multi-argument lambdas that do arbitrary pattern matching, without problematic syntax like this:

\(Just x) (Just y) -> x + y; _ _ -> 1

However, it does mean that we would have to parse rather differently than a standard case. For example this would not be valid:

\case { Just x -> 1 }

Because it would parse as a two argument function with the second argument bound to x and the first argument bound to the invalid name Just.

comment:14 Changed 4 years ago by igloo

  • Milestone set to 7.2.1

comment:15 Changed 4 years ago by liyang

  • Cc hackage.haskell.org@… added

comment:16 Changed 4 years ago by uzytkownik

  • Cc uzytkownik2@… added

comment:17 Changed 4 years ago by spl

  • Cc leather@… added

comment:18 Changed 4 years ago by illissius

  • Cc illissius@… added

the downside is that we have to adjust our mental parsers/typecheckers to recognise if then and case of as a lambda, and I'm not sure the gain in brevity is worth the loss of readability

My own gut feel is that it's a lot better to have an initial symbol to say "here comes a function".

I don't think I agree with this. Maybe the word 'lambda' in the name of the proposal is misleading; I don't think the intuition here should be that of a lambda. I think it should be (and was originally) partial application. I think it's very natural for any Haskell programmer that if you have a function, and you apply it less than fully, that what you end up with is a function. The only difference here is that the argument sits in between the 'case of' rather than after the name of the function, but I don't think that's a big obstacle; it's universally obvious that case-of is special. I think the originally proposed 'case of' syntax is elegant and intuitive.

I'm much more ambivalent about if-then-else. It would make sense for completeness's sake, but it's a lot uglier (due to having multiple unorthodoxly-positioned arguments) and I don't see nearly as much of a use case. (It also, unlike 'case of', doesn't feel intuitive -- this is just a gut feel and I don't really have any arguments to explain why, but then again, the only real definition of intuitivity is whether people feel that way...) I think I'd rather just put ifThenElse in the Prelude and have people use that if they want to partially apply it (which isn't possible with case-of).

comment:19 Changed 4 years ago by mikhail.vorozhtsov

I ported Max's patch to (one-argument) \case syntax. I haven't touched alternative layout rules as I'm not familiar with them. Please review.

This syntax can be later extended to handle multiple arguments:

\case
  Just x, Just y -> e1
  Just x, _      -> e2

which would be translated to

\a b -> case (a, b) of
  (Just x, Just y) -> e1
  (Just x, _)      -> e2

What do you think?

comment:20 Changed 4 years ago by mikhail.vorozhtsov

  • Cc mikhail.vorozhtsov@… added

comment:21 Changed 4 years ago by simonmar

I think it would be disappointing if we couldn't do multi-argument functions this way. I like Max's suggestion in comment:13:

\case { (Just x) (Just y) -> x + y; _ _ -> 1 }  ==> \a b -> case (a, b) of { (Just x, Just y) -> x +y; (_, _) -> 1 }

Admittedly the syntax differs from a case expression, which could be confusing. So perhaps it should be \let instead? Or maybe we should just bite the bullet and pick a new keyword, e.g. fun?

comment:22 follow-up: Changed 4 years ago by simonpj

Another idea:

  • With LambdaCase, make plain "\" into a layout herald.
  • Allow multiple arguments as in Simon's comment above.

Something like \x y -> x+y would expand to \{x y -> x+y} so existing code would mostly be fine, even with the extension on. But not all existing code:

   f x $ \y ->
   g y $ \z ->
   blah

but maybe we don't care. With the extension on you could still use explicit curlies:

   f x $ \{y ->
   g y $ \{z ->
   blah }}

We don't like lambda-if, so let's not do that yet.

Then mif and mcase can be coded reasonably easily

do { ....
   ; doesFileExist "foo" >>=
     \ True -> do { ... file does exist ... }
       False -> do { ...it doesn't }
   ; ... }

comment:23 in reply to: ↑ 22 Changed 4 years ago by mikhail.vorozhtsov

Replying to simonpj:

>    f x $ \y ->
>    g y $ \z ->
>    blah

Scary. It happens that I'm doing exactly that (replace $ with >>=ᵢ).
I also think that \ is just too "small" of a token to start a new layout.
I remember someone on the list suggesting the following syntax:

\ p1, p2 -> e1
| p3, p4 -> e2

which I find more graphic.

Why don't we just have both, as different extensions (MultiClauseLambda)? The original proposal is about writing a good ol' case and letting the compiler sugar a lambda in, and one-arg \case is a perfect fit for the job.

At times like this I wish one could just upload a "plugin" package to Hackage and let the people decide...

comment:24 Changed 4 years ago by simonmar

Having re-read the Haskell cafe thread and after discussing this with Simon yesterday, I'm convinced that the multi-clause lambda approach is the cleanest extension of the language.

  • \case is out: either it supports a single-argument lambda only, which would be inconsistent with \, or it supports multi-argument lambda, which would be inconsistent with case.
  • | to separate clauses is out: | is already used for guards, so this is an inconsistency
  • , to separate arguments is out: nowhere else in the syntax uses comma to separate arguments
  • case of is out: it doesn't look like a lambda (I don't buy the partial application argument of comment:18, since for there to be a partial application there has to be a function, and there isn't one here)

In favour of multi-clause lambda:

  • it is more generally useful than mcase or case<-.

Against:

  • It is a change to the syntax. But it will be optional, so it only breaks existing code if you explicitly enable it.

Arguably having \ introduce layout is an improvement, because it enforces the requirement that the lambda binding scopes over code to the right and below.

There is one alternative design that does make sense: leave \ as it is and choose a new keyword for multi-clause lambda, e.g. fun (or, cheekily, λ). This would have the disadvantage that there would be two constructs for anonymous functions (too much syntax), I think we should try out multi-clause \ first and see how well it works in practice.

comment:25 follow-up: Changed 4 years ago by rl

Do I understand correctly that the RHS of

f = \x -> x
  z

would be parsed as (\x -> x) z with the extension?

comment:26 in reply to: ↑ 25 Changed 4 years ago by simonmar

Replying to rl:

it would parse as

f = \ { x -> x
 } z

which is a syntax error.

comment:27 Changed 4 years ago by rl

Sorry, I meant

f = \x -> x
  $ z

I would expect this to parse as (\x -> x) $ z with the extension, analogously to, say,

f = case x of x -> x
  $ z

But this would mean that the extension might actually silently change the meaning of existing code rather than breaking it which seems quite undesirable.

comment:28 Changed 4 years ago by simonmar

Correct, it will parse as (\x -> x) $ z, and indeed this might silently change the meaning of existing code. It's unlikely in this case, because x and (\x -> x) will have different types, but you could probably construct an example where the types are the same.

case and do already behave like this, whereas let and if behave the other way (munching up the $ z). The multi-clause lambda extension would move \ from the latter group to the former.

comment:29 Changed 4 years ago by rl

FWIW, I don't like the layout approach, especially given the above. I somewhat wonder if this would ever be ambiguous (layout doesn't matter)?

    \p1 p2 -> e1
    \p3 p4 -> e2

comment:30 Changed 4 years ago by simonmar

I can't think of any ambiguities with that, but it feels a bit strange, I suppose because it looks like two separate lambda expressions.

comment:31 follow-up: Changed 4 years ago by claus

Some of the syntax suggestions here scare me. But even if an unproblematic syntax could be found, do you really want to add a complex language construct with limited usage pattern? One nice thing about Haskell is that it tries to keep code programmable/library-based, with only minimal support through syntax built-ins.

I would like a 'case'-as-a-function variant, especially if it is more basic than the current 'case-of' (ie, the 'case-of' can be defined in terms of 'case', so the language does not get any bigger, just more flexible).

While I'm here: have you looked at introduce lambda-match (explicit match failure and fall-through), from around the same time as lambda-case? At the time, it was implemented as a small parser modification, with most of the functionality in a library (see ticket attachments for patch, library, and some examples), and 'case'-as-a-function was easy to implement in terms of it. But it also supported other useful programming patterns.

comment:32 Changed 4 years ago by lelf

  • Cc anton.nik@… added

comment:33 in reply to: ↑ 31 ; follow-up: Changed 4 years ago by simonmar

Replying to claus:

Some of the syntax suggestions here scare me. But even if an unproblematic syntax could be found, do you really want to add a complex language construct with limited usage pattern?

I'm really surprised by both "complex language construct" and "limited usage pattern" here, since those are both issues that I thought the proposal addresses quite well.

  • complex: we're re-using existing syntax and translations. The specification should be entirely straightforward (thought admittedly I haven't tried writing it down yet). The syntax is consistent with the rest of the language; it seems to me a natural generalisation. It's just an anonymous version of multi-equation function definitions, and the syntax is exactly what you'd expect.
  • limited usage pattern: it covers all the use cases that came up in the discussion: lambda-case, lambda-if (both with multiple arguments) and also mcase and mif.

While I'm here: have you looked at introduce lambda-match (explicit match failure and fall-through), from around the same time as lambda-case? At the time, it was implemented as a small parser modification, with most of the functionality in a library (see ticket attachments for patch, library, and some examples), and 'case'-as-a-function was easy to implement in terms of it. But it also supported other useful programming patterns.

Yes, I remember it, though I'd have to go and review the discussion to fully understand the motivation. On the face of it the syntax looks a bit strange (vertical bar is re-used).

comment:34 in reply to: ↑ 33 Changed 4 years ago by claus

Replying to simonmar:

I'm really surprised by both "complex language construct" and "limited usage pattern" here, since those are both issues that I thought the proposal addresses quite well.

"complex", as in made of many parts. Perhaps "monolithic" would be more to the point. As for "limited usage pattern", I am not doubting the use case for lambda-case (I'd use it myself). I am merely concerned that we have a growing number of complex/monolithic language constructs, with partially overlapping feature sets. Each of those language constructs covers one (class of) use case(s), but we cannot keep adding language constructs for each new use case.

If we could instead work out and expose the building blocks for these language constructs, then a small set of building blocks could cover all use cases. In other words, I'd like to see reuse not just by copy-and-modify of "existing syntax and translations", but by having language constructs that cover the shared features, with more complex language constructs being defined in terms of those simpler constructs (defining case-of in terms of case-as-a-function might be the most direct way to achieve that, as far as this ticket is concerned, but case-of really wants to be broken into smaller parts in the long run).

.. lambda-match (explicit match failure and fall-through)..

Yes, I remember it, though I'd have to go and review the discussion to fully understand the motivation. On the face of it the syntax looks a bit strange (vertical bar is re-used).

Motivation in brief, in the context of this ticket: instead of turning monolithic case into a function, turn each case alternative into a function, and provide the means to recombine the alternatives.

It was really hard to find non-ambiguous syntax - the vertical bar was to remind of algebraic datatype alternatives, but |pattern->body alone had a corner case of ambiguity, so it became (|pattern->body) instead. Adding guards back in ended up with (|pattern | guard -> body). That wasn't ideal, but read fairly well when using lambda-matches as case alternatives.

I don't think it is necessary to go that way for this particular ticket, but those who are showing interest in this ticket might find lambda-match interesting as a next step.

comment:35 Changed 4 years ago by simonpj

It's true that the proposal we outline above is monolithic in the sense that it's not composed of smaller parts. But it is particularly simple in another way: every part of GHC from the parser onwards already implements lambda-case! The matching part of a lambda, of a case expression, and of a multi-case function definition, are all defined using a MatchGroup (see HsExpr.lhs). All that lambda-case does is provide concrete syntax to let you get at the abstract syntax that is already there. So it just "fills the gap" as it were.

A more compositional approach to pattern matching is indeed an interesting topic. There have been a number of approaches propoed including yours. (Barry Jay's book is a more radical take on the subject.) But there isn't a clear winner yet.

So I think lambda-case is a fine candidate to fill the syntactic gap for now, leaving something more ambitious for the future.

Simon

comment:36 Changed 4 years ago by mikhail.vorozhtsov

Pretty printing gets somewhat ugly because we need to treat the first Match differently.

comment:37 Changed 4 years ago by simonmar

  • Milestone changed from 7.4.1 to 7.2.1
  • Priority changed from normal to high

Patch looks great, thanks Mikhail! We just need a test, and we can put it into 7.2.1.

comment:38 Changed 4 years ago by claus

I'd vote for requiring explicit braces for multi-clause-lambdas - better than breaking so much \-code. Perhaps ask for feedback on ghc-users, or where the mailing list threads were?

comment:39 Changed 4 years ago by simonmar

Frankly there's already been a great deal of feedback - this particular design was actually discussed in the most recent haskell-cafe thread and got a fair few +1s. I think it's now time to put it in and see how well it works in practice.

Remember, no code will actually break unless you explicitly ask to turn on the extension.

comment:40 Changed 4 years ago by mikhail.vorozhtsov

Fixed a bug, added compatibility with WarnIncompletePatterns (multi-clause lambdas now are treated as case expressions in that regard).

comment:41 Changed 4 years ago by mikhail.vorozhtsov

I think we should use a different symbol/keyword after all. The new layout rule is great for multi-clause abstractions, but often gets in the way in the single-clause case, e.g.

mask $ \restore -> do
  blah
  blah
  blah

needs to be rewritten as

mask $ \
  restore -> do
  blah
  blah
  blah

comment:42 Changed 4 years ago by mikhail.vorozhtsov

Added support for 'where' bindings in alternatives. What about guards?

comment:43 Changed 4 years ago by mikhail.vorozhtsov

Enabled guards.

comment:44 Changed 4 years ago by igloo

  • Status changed from new to patch

comment:45 Changed 4 years ago by igloo

  • Owner set to igloo

comment:46 Changed 4 years ago by igloo

  • Milestone changed from 7.2.1 to 7.4.1

comment:47 Changed 4 years ago by mikhail.vorozhtsov

comment:48 follow-up: Changed 4 years ago by simonpj

Thanks for rebasing. The only issue here is one of syntax. Several people have expressed anxiety about making so quiet a symbol as "\" into a layout herald, and have showed that some existing code might break.

So, what to do? One possibility is not to make "\" into a symbol introducing implicit layout, but still to allow explicit layout with braces and semi-colons. Thus:

   \ { True -> e1; False -> e2 }

would be ok. But this would not be ok

    \ True -> e1
      False -> e2

That seems like a reasonable compromise. Using the brace/semicolon stuff is compatible with the way case expressions work, which is a Good Thing. Any comments?

Simon

comment:49 in reply to: ↑ 48 Changed 4 years ago by mikhail.vorozhtsov

Replying to simonpj:

Thus:

   \ { True -> e1; False -> e2 }

would be ok. But this would not be ok

    \ True -> e1
      False -> e2

That seems like a reasonable compromise. Using the brace/semicolon stuff is compatible with the way case expressions work, which is a Good Thing. Any comments?

Ugh. This is getting uglier and uglier. I've been using the current version of the patch for some time and I think the syntax has two major problems:

  1. It rejects the nice-looking indentation we are all used to in the single-clause case (see my 'mask' example above).
  1. It looks like a case expression, but has different pattern syntax, i.e. I constantly write
    foo >>= \
      Nothing -> ...
      Just a  -> ...
    

instead of the correct

foo >>= \
  Nothing  -> ...
  (Just a) -> ...

Explicit layout solves the first issue, IMO, at the expense of graphic clarity. I mean

foo >>= \
  { Nothing  -> do
      abc
      def
  ; (Just a) -> do
      abc
      def
  }

just makes my eyes hurt. Do we really want a feature that is only accessible using explicit layout?

I think the fact that single- and multi-clause lambdas require different indentation rules (and we can't look ahead to distinguish them) tells us to use a different token (\fn, \fun, \let?). I'd also say that \x -> case x of ... (or x <- foo; case x of ...) is such a common idiom that it deserves its "anonymous" counterpart (with respect to pattern syntax) regardless of the whole multi-clause lambda thing.

comment:50 follow-up: Changed 4 years ago by simonpj

Concerning (1) I don't understand. If you don't put a curly brace, everything would happen just like now... so mask would be fine.

Concerning (2), yes, I am suggesting that this feature is only accessible using explicit layout. It's not perfect, but the alternatives seem worse to me.

Does anyone else have other concrete proposals? If so, let's hear them.

The default alternative is to do nothing.

Simon

comment:51 in reply to: ↑ 50 Changed 4 years ago by mikhail.vorozhtsov

Replying to simonpj:

Concerning (1) I don't understand. If you don't put a curly brace, everything would happen just like now... so mask would be fine.

Yes. I was referring to the syntax implemented in the patch.

Does anyone else have other concrete proposals? If so, let's hear them.

Let me bug you one last time. Please consider adding \case expressions in addition to multi-clause lambdas. Сase expressions are at the fingertips of every haskeller, not having their "anonymous" version will (and in my case already is) lead to constant stumbling (due to different pattern syntax). Besides, we already have that sort of duplication for one-argument named functions (fun P = ... vs fun x = case x of P -> ...).

comment:52 Changed 4 years ago by simonmar

I don't like the explicit layout idea. The goal so far has been to find a way to allow multi-clause multi-argument anonymous functions but without adding any inconsistencies to the language. Having \ introduce a layout context fits the bill, but unfortunately it breaks many common idioms.

Perhaps the only way to do this is to have a new keyword.

comment:53 Changed 4 years ago by mikhail.vorozhtsov

We could use "\" + "map" as the starting lexemes. It is uncommon to name an argument "map" due to the overshadowing warning. Of course, in all other contexts "map" would be just an identifier.

comment:54 Changed 4 years ago by zzo38

I suggest using "case of" for the lambda-case. For two arguments, you can use "curry case of"

comment:55 Changed 4 years ago by igloo

  • Milestone changed from 7.4.1 to 7.6.1

Punting

comment:56 Changed 3 years ago by dterei

  • Cc dterei added

comment:57 Changed 3 years ago by jeltsch

  • Cc g9ks157k@… added

comment:58 Changed 3 years ago by jeltsch

It would be good if we had something analogous for proc from arrow notation. This seems to rule out the partial application solution case of …, but seems to go well with the multi-clause lambda, since we could also have a multi-clause proc.

comment:59 Changed 3 years ago by simonpj

  • difficulty set to Unknown
  • Owner igloo deleted
  • Priority changed from high to normal
  • Status changed from patch to new

Although we have a concrete proposal here for multi-clause lambdas and lambda-case, and a patch, we just aren't yet convinced enough that the (modest) increase in language complexity is justified by the (modest) benefits. Especially as some common idioms using lambda no longer work with the change. This isn't a definite "no", but we'll downgrade the priority until we can find a better solution.

comment:60 follow-up: Changed 3 years ago by mikhail.vorozhtsov

It would be reasonable to split multi-clase-lambdas into a separate ticket, so that each feature can be discussed in a clearer context of pros and cons (e.g. lambda-case does /not/ break any idioms). What do you think?

I've been using lambda-case at work for a year and never looked back to tmp1,tmp2,...[1] But patching GHC every time /is/ irksome. I even started to think about replacing GHC lexer/parser with modular (combinators-based) analogs, to allow compiler plugins to hook into parsing.

[1] I write a lot of code like this:

await (event1 .?. event2 ... eventN) >>= \case
  (elem0 -> Just v) -> ...
  (elem1 -> Just v) -> ...
  ...

If you do it without \case, temporary bindings can easily go into tmp10+ in a single function.

comment:61 Changed 3 years ago by simonpj

Thanks. Yes, I think that part of the difficulty is that this ticket is 60 comments long; it dicusses more than one feature; for each feature it discusses more than one design; and Simon and I are deeply under water with other aspects of GHC, which makes it hard to devote attention to new features.

So yes, start a new ticket. Write a wiki page that explains the proposal you actually advocate (give links to other competing proposals you rejected). Explain pros and cons. Add a link from http://hackage.haskell.org/trac/ghc/wiki/Commentary. Encourage comment on ghc-users.

I must say that \case... looks more attractive to me, because there is a clearly visible herald, using a keyword that otherwise cannot appear there. And that point had become submerged (for me) in the detail of this thread.

comment:62 in reply to: ↑ 60 Changed 3 years ago by jeltsch

Replying to mikhail.vorozhtsov:

It would be reasonable to split multi-clase-lambdas into a separate ticket, so that each feature can be discussed in a clearer context of pros and cons (e.g. lambda-case does /not/ break any idioms).

If you open a separate ticket for this, then please link to it here, so that I get notified about this new ticket.

comment:63 follow-up: Changed 3 years ago by simonmar

Rather than a single new proposal, I think what would be most useful would be a summary of the previous proposals and their pros and cons, so that we don't have to rediscover all this.

e.g. we previously didn't like \case because we wanted a way to have multiple arguments too: lambda currently allows multiple arguments, and \Just x -> is a function of two arguments, whereas \case Just x -> is a function of one argument. I'm not necessarily discounting the idea on this basis, but it is arguably an inconsistency.

Another alternative is to introduce a new keyword for anonymous multi-clause multi-argument functions, e.g. fun.

comment:64 in reply to: ↑ 63 Changed 3 years ago by jeltsch

Replying to simonmar:

Another alternative is to introduce a new keyword for anonymous multi-clause multi-argument functions, e.g. fun.

Note that when introducing a new construct for functions, we should introduce an analog construct for arrows. If we introduced a new keyword fun for functions, we would have to introduce another new keyword for arrows. If we would reuse \ as in \ case, we could reuse proc in the same way (proc case). This is not to say that I particularly like the proposal with \ case, but that the syntactic construct that we come up with should reuse \.

comment:65 Changed 3 years ago by mikhail.vorozhtsov

I just wrote a wiki page. Editing (my english sucks) and improvements are welcome.

comment:66 Changed 3 years ago by simonmar

Thanks for the wiki page, that helps a lot!

FWIW, OCaml has both \ and \case, called respectively fun and function. It does not have a multi-argument multi-equation anonymous function construct. (ref: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html).

I'm hesitant to express any more opinions at this stage, but now that we've explored the design space quite thoroughly I'm feeling more inclined towards \case.

Changed 3 years ago by mikhail.vorozhtsov

Multi-clause lambda abstractions extension, v4, another rebase

Changed 3 years ago by mikhail.vorozhtsov

Tests for the MultiClauseLambdas extension, v2, another rebase

comment:67 Changed 3 years ago by mikhail.vorozhtsov

I started a new thead on the GHC Users list. Hop in!

comment:68 Changed 3 years ago by simonpj

  • Description modified (diff)
Note: See TracTickets for help on using tickets.