Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Haskell's where in switch structure #582

Open
haskellcamargo opened this issue Oct 14, 2014 · 9 comments
Open

Feature Request: Haskell's where in switch structure #582

haskellcamargo opened this issue Oct 14, 2014 · 9 comments
Labels

Comments

@haskellcamargo
Copy link

It will be very good if we can have where in switch structures, like occurs in Haskell, like we use in that.
The possible LiveScript syntax could be:

get-data = (x) ->
| word is 'hello' => word |> replicate 2
| word is 'bye'   => word |> reverse
| otherwise       => word
where word = x

That would compile to:

get-data = function(x) {
var word = x;
switch(false) {
  case !(word === 'hello'):
    return replicate(2)(word);
  case !(word === 'bye'):
    return reverse(word);
  default:
    return word;
  }
};

This would be awesome!

@apaleslimghost
Copy link
Contributor

We used to have this, it was removed in 1.2

@gkz
Copy link
Owner

gkz commented Oct 15, 2014

The above example wouldn't have worked with the old where clause

@dead-claudia
Copy link
Contributor

This could potentially be very powerful with more complicated match and switch clauses:

checkData = (data) ->
  for own key, field of data
    [ key
      field
      match field
        | sep '@' => 'user'
        | sep '#' => 'topic'
        | _ => 'none'
        where sep = -> (field.indexOf it) != 0]

which would compile to something similar to:

var own$ = ().hasOwnProperty;
var checkData = function(data) {
  var key, field, results$ = [];
  for (key in data) {
    if (own$.call(data, key)) {
      field = data[key];
      results$.push([key, field, fn$(field)]);
    }
  }
  return results$;
  function fn$(field){
    function sep(it){
      return field.indexOf(it) !== 0;
    }
    switch (false) {
    case !sep('@')(field):
      return 'user';
    case !sep('#')(field):
      return 'topic';
    default:
      return 'none';
    }
  }
};

I know that the above example is technically equivalent to the following, but it's a bit cleaner IMO, even in this theoretical (and potentially not the best) use case.

checkData = (data) ->
  sep = -> (field.indexOf it) != 0
  for own key, field of data
    [ key
      field
      match field
        | sep '@' => 'user'
        | sep '#' => 'topic'
        | _ => 'none' ]

@dead-claudia
Copy link
Contributor

Here's a specific real-world case I found can simplify my own code drastically:

# original
checkMatch = (node, format) ->
    type = typeof format

    if typeof node != type
        return false

    switch type
        | 'function' => format node
        | 'object' =>
            (if Array.isArray format
                checkArray
            else
                checkObject) node, format
        | _ => format == node

# with this proposed syntax
checkMatch = (node, format) ->
    | type != typeof node => false
    | type == 'function' => format node
    | type == 'object' =>
        (if Array.isArray format
            checkArray
        else
            checkObject) node, format
    | _ => format == node
    where type = typeof node

They should compile nearly identical.


<aside>
At least I'm not writing it in vanilla JavaScript...

function checkMatch(node, format) {
    var type = typeof format;

    if (typeof node !== type)
        return false;
    else if (type === 'function')
        return format(node);
    else if (type === 'object')
        return (Array.isArray(format) ? checkArray : checkObject)(node, format);
    else
        return node === format;
}

</aside>

@dead-claudia
Copy link
Contributor

I would suggest the following syntax (in a hopefully self-explanatory context-free grammar):

case = one of:
    "|"
    "when"
    "case"


then = one of:
    "then"
    "=>"


default = one of:
    "default"
    case "otherwise"
    case "_"


where = "where"


case-statement =
    case expression then body


case-list =
    case-statement
    case-list


case-list =
    case-statement


default-statement =
    default then body


where-assign =
    variable "=" assignment-expression


where-list =
    where-assign
    where-list


where-list =
    where-assign


where-statement =
    where where-assign


where-statement =
    where line-break
    where-list


switch-body =
    case-list


switch-body =
    case-list
    default-statement


switch-body =
    case-list
    where-statement


switch-body =
    case-list
    default-statement
    where-statement


(This is for `switch`, `match`, `->`, etc.)

switchlike-body =
    then INDENT(switch-body) <-- indentation required for switch-body

If something isn't quite clear, or if I've screwed something up, I'm all ears.

@yazla
Copy link

yazla commented Mar 25, 2015

So is this moving anywhere? I am curios, why was the "where" structure removed from the livescript, what was the reasoning? it is pretty useful as for me.

@dead-claudia
Copy link
Contributor

I get the feeling this is something waiting on a patch I don't have time to write at the moment.

@dead-claudia
Copy link
Contributor

@gkz @vendethiel What do you think of this syntax? I'm aware it deviates from the old where clause, but it's more inspired from Haskell's where. OCaml and F# have similar.

I don't have time to write a patch for this currently, but I may experiment with the compiler later on, and this would be interesting.

What do you all think? Is there anything I missed or made a mistake on in the idea itself?

@vendethiel
Copy link
Contributor

It doesn't really matter to me. The syntax in the first post is gonna be a huge issue, tho. We're reaching the limits of implicit blocks, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants