NeoMent
NeoMent

Reputation: 176

Elm 0.19 Maybe.withDefault

I have read the documentation, but i still don't understand how to Maybe.withDefault in my code. Because from a String.toInt I get Maybe Int, I cant use a + sign to add the values I try to convert into Integers. This is Elm 0.19. How can I fix this?

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)


main =
  Browser.sandbox { init = init, update = update, view = view }


-- MODEL

type alias Model = {mainNum : String, curNum : String}

init : Model
init =
  {
      mainNum = ""
      ,curNum = ""
  }

-- UPDATE

type Msg = AddNum String | Add | Clear 

update : Msg -> Model -> Model
update msg model =
  case msg of
    AddNum number ->
        {model | curNum = model.curNum ++ number}

    Add ->
        {model | curNum = String.fromInt ((String.toInt model.curNum) + 
(String.toInt model.mainNum))}

    Clear ->
        init



-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ div [] [ text  model.curNum]
    , button [ onClick (AddNum "1" )] [ text "1" ]
    , button [ onClick (AddNum "2" )] [ text "2" ]
    , button [ onClick (AddNum "3" )] [ text "3" ]
    , div [] []
    , button [ onClick (AddNum "4" )] [ text "4" ]
    , button [ onClick (AddNum "5" )] [ text "5" ]
    , button [ onClick (AddNum "6" )] [ text "6" ]
    , div [] []
    , button [ onClick (AddNum "7" )] [ text "7" ]
    , button [ onClick (AddNum "8" )] [ text "8" ]
    , button [ onClick (AddNum "9" )] [ text "9" ]
    , div [] []
    , button [ onClick (AddNum "0" )] [ text "0" ]
    , button [ onClick Clear] [ text "Clear" ]
    ]

Upvotes: 1

Views: 2092

Answers (4)

Karol Samborski
Karol Samborski

Reputation: 2955

Regarding your question:

  1. String.fromInt returns Maybe Int, it means that the value can be either Just Int or Nothing
  2. You cannot just add e.g. Just 1 and Nothing together or even Just 1 and Just 2
  3. You need to extract the number from Just 1 somehow or specify default value if it's Nothing (e.g. 0).
  4. This is where Maybe.withDefault comes in handy. It can extract Int from any Maybe Int (doesn't matter if it's Nothing or Just). It takes 2 parameters:

    • first is the default value that is used when the second parameter is Nothing
    • second is the actual Maybe value

So in your code you can use it like this:

{model 
  | curNum = 
      String.fromInt <|
        (Maybe.withDefault 0 <| String.toInt model.curNum) 
        + (Maybe.withDefault 0 <| String.toInt model.mainNum)
}

Having said all this you could just save all the trouble by using Ints in your model and String.fromInt in your views.

Upvotes: 2

Khoa
Khoa

Reputation: 2932

withDefault : a -> Maybe a -> a

This is a function received 2 params (the last one is the returned value).

If a is an Int then we have:

withDefault : Int -> Maybe Int -> Int

-- if `a` is a `Float` then we have
withDefault : Float -> Maybe Float -> Float

-- in general, if `a` is an `X` then we have
withDefault : X -> Maybe X -> X

The 1st param is the one that will be returned once the 2nd param is Nothing.

So if the 2nd param isn't Nothing then the function will return the value inside 2nd param.

so basic example:

-- hard-code 2nd param
withDefault 10 (Just 20) -- this function call results 20
withDefault 10 Nothing -- this function call results 10

advanced ones:

-- 2nd param is Nothing
withDefault 10 (String.toInt "abc") -- this function call results 10

-- 2nd param is not Nothing
withDefault 10 (String.toInt "123") -- this function call results 123

into your code:

Add ->
    let
        cur : Int
        cur =
            Maybe.withDefault 0 (String.toInt model.curNum)

        main : Int
        main =
            Maybe.withDefault 0 (String.toInt model.mainNum)
     in
     { model | curNum = String.fromInt (cur + main) }

As you can see, the Maybe.withDefault makes sure you always receive Int for your add returned Int calculation.

Without it, you will always receive Maybe Int and the add of Maybe Int will always returns Maybe Int.

Note: My code above is only for Maybe.withDefault usage explanation, not for production code

Upvotes: 4

NeoMent
NeoMent

Reputation: 176

I have fixed the error by creating a function that converts Maybe Int -> Int:

checkInt : Maybe Int -> Int
checkInt x = case x of
    Just y -> y
    Nothing -> 0

Upvotes: 0

Simon H
Simon H

Reputation: 21007

You do need a string with text but your onClicks can work with messages that take Ints. i.e.

button [ onClick (AddNum 7)] [ text "7" ]

I suggest you change your model to work with ints too, and then you won't have to do any conversion from/to strings at all

Upvotes: 1

Related Questions