Using 2 case under an else

I am a bit confused as to how to get multiple checks under an else. I freely admit I am a total newbie with Elm and am more used to Python etc.

I have the following construct

If
 
Else
 Case
 Nothing ->
 Just ->

And this works as expected. However I wish to add a second case under the else (which also works fine on its own) so that both case statements are evaluated and the action performed. This is probably a huge no no but I am amending existing code and this seems like it should be straightforward.

What do you mean by “the action performed"? If they’re returning a Cmd, you can use Cmd.batch to combine them

Also, looking at your example: if you need to case/of two Maybe’s you can pair them with a tuple:

foo: (Maybe Int) -> (Maybe Int) -> Int
foo a b =
    case (a, b) of
        (Just x, Just y) -> 
            x + y
        (_, _) ->
            -- A sensible default
            0

You could also use Maybe.map2 ( Maybe - core 1.0.5 ) which will keep the Maybe value after the transformation.

I realise I should probably have been clearer, my apologies.

Case 1 - check for a thing, if so then do action 1.

Case 2 - check for a different thing, if so then do action 2.

To be fair, this is using elm as a controller for doing things with the mouse etc so it’s not the traditional use case of a web page.

The existing code has

If <thing>

<.. stuff .. >

Else

<case 1> as described above

Under the else is the right place for Case 2. Otherwise I would just have to duplicate the whole If Else again.

I think we still need more detail about what you mean by “do action”. Elm is a pure language, meaning there are no side effects. An if or case expression alone will not perform any actions in the existing or new code.

Here is a better description of the code …

                                                            case
                                                                <checkthing>
                                                                    |> List.filter (.isActive >> Maybe.withDefault False >> not)
                                                                    |> List.head
                                                             of
                                                                Nothing ->
                                                                    <debug text>
                                                                
                                                                Just 
                                                                    <click a button on screen>

The same idea for the second case except it’s checking a different condition and then using a context menu right click.

In this case the ‘actions’ are the interacting with the UI (the mouse click or context menu) and the two case conditions are different but I wish both to happen under that else.

Would it work to return a list of actions instead of a single action? That way you can do:

if
  [ <.. stuff ..> ]
else
  [ case <...> of
      Nothing -> <debug text>
      Just _ -> <click a button on screen>
  , case <...> of
      Nothing -> <debug text>
      Just _ -> <right click a button on screen>
  ]

Won’t compile and the syntax looks right.

The 2nd branch of this `if` does not match all the previous branches:

Now, that will be because I didn’t wrap the if in to make them both lists but if I do that then it throws another compile error because of the outside wrapping of the if. Again, I am a newbie at Elm but this seems unnecessarily hard. I obviously can’t share the code directly or I would have already.

The if is in a structure of

{ a = 
   if 
     <stuff>
   else
     case <etc>
}

Hi,

Yeah all the branches need to return the same type. So it looks like the structure that you need is:


{ a =
    if <something1> then
      <stuff>
    else 
      case <something2> of
         <match1> ->
            <stuff>
         <match2> ->
            <stuff>

         _ ->
            <stuff>
}

HTH

Hi,

Thanks for the suggestion but I think you may have missed that there is two different things to case.

I need to .

{ a =
if <check something> then 
  <some stuff>
else
  case <another different thing>
  Nothing -> <debug text>
  Just -> <do some stuff involving a mouse click>
  case <check a totally different thing>
  Nothing -> <debug text>
  Just -> <do some other stuff involving a right click to context menu>
 }

I get I am explaining all this really badly!

Then you can do what @passiomatic suggested and case on a tuple.

However, to clarify, do <some stuff>, <debug text>, <do some stuff involving a mouse click>, <do some other stuff involving a right click to context menu>all return the same Type?

If not you’ll need to re-think, or maybe provide more detailed information regarding what the types are.

I believe the misunderstanding comes from the fact that @LusiElm tries to think like in JavaScript, at the level of a view function:

// I assume emailDisplay, warningModal and contextMenu are IDs of elements in the DOM
document.forms[0].addEventListener('submit', (ev) =>
{
    const emailInput = ev.target.email

    if(/@example.com$/.match(emailInput.value))
        // This is View Logic
        document.emailDisplay.innerText = 'We\'ve got an email';
    else
    {
        switch(something)
        {
            case 1:
                // This is Control logic and view logic
                document.warningModal.show();
                document.emailDisplay.innerText = 'We\'ve got no email';
                break;
            case 2:
                // This is Control logic
                document.contextMenu.show();
                break;
        }
    }
}

My understanding is that In Elm, you would make that a control function where:

  • the first branch issue a command that modify the model the emailDisplay view is mirroring
  • the second branch return two batched commands
  • the third branch would issue a command to show the context menu

Every time you end up modifying the model so it would be reflected in the view, you never act directly on the DOM.

1 Like

The typing is fine. Either case works on its own.

ie if I have

{ a =
if <check something> then 
  <some stuff>
else
  case <another different thing>
  Nothing -> <debug text>
  Just -> <do some stuff involving a mouse click>
 }

That works. Or if I have

{ a =
if <check something> then 
  <some stuff>
else  
  case <check a totally different thing>
  Nothing -> <debug text>
  Just -> <do some other stuff involving a right click to context menu>
}

That also works. I just can’t find a way to have both.

Looks like you need to match on the tuple then :slight_smile:


{ a =
if <check something> then 
  <some stuff>
else  
  case (<another different thing>,<check a totally different thing>) do
      (Nothing, Nothing) ->
          <do some stuff when neither match>
      (Just _, Just _) -> 
          <do some stuff when both match>
      (Just _, Nothing) ->
          <do some stuff when left side matches>
      (Nothing, Just _) ->
          <do some stuff when right side matches>
}


Hey there, welcome to Elm! If i understand your problem correctly, then it’s a problem with the result type you want to work with and the type the code currently works with. You said it’s currently kind of looking like this?

a : ???
a =
  if checkSomething then
    someStuff
  else
    case checkDifferentThing of
      Nothing ->
        debugText

      Just _ ->
        rightClickContextMenu

I hope i’m not being too obvious when i say that the three values / functions / whatever you want to call them someStuff, debugText and rightClickContextMenu all have to be of the same type. I wrote ??? above, but you can check in your code what it’s actually called. You make it sound like it’s some kind of Action type, so i will continue with that.

Now your problem is, that you want your else-Branch to not return a single Action now, but instead a List Action - and that’s not compatible with whoever is calling this a-thing. You would have to change your caller to work with that.

Hope that helps?

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.