Search code examples
functional-programmingelmside-effects

elm - executing multiple lines in a function


In elm, is something like the below possible

foo : Int -> Html
foo inputNum =
  addToNumHistory inputNum ;
  display inputNum

where the aim of the above is to execute multiple lines of code?

If not, is this because the above is an example of a side effect?

If something like the above syntax is not possible, how would one go about executing two functions/lines of code simultaneously, as in the above, or as a result of a given input (case branch) ?

Edit

The above is a bad example. The following uses the Elm Architecture:

--Model
type alias Model =
  { number : Int
  , numberHistory : List Int
  }

type Action
  = Number Int


--Update
update : Action -> Model
update action =
  case action of
    Number num->
      addToNumHistory num           

addToNumHistory : Int -> Model -> Model 
addToNumHistory num modelHistory =
  { model 
    | number = num
    , numberHistory = num :: model.numberHistory
  }

--View     
view : Signal.Address Action -> Model -> Html
view action model =
  div []
    [  field 
       "text" 
       address 
       Number model.number
       "Enter lucky number here pal!"
       model.number 
    ]

Given this, am I right in presuming that to 'execute multiple lines' in such a fashion as to alter an underlying model, one would simply use/extend the model - for example, to effect a change analogous to the following:

--Update
update : Action -> Model
update action =
  case action of
    Number num->
      addToNumHistory num;
      addToChangeHistory

one would simply extend the model as follows:

--Model
type alias Model =
  { number : Int
  , numberHistory : List Int
  , changeHistory : List Date
  }

--Update
update : Action -> Model
update action =
  case action of
    Number num->
      addToNumHistoryWithChangeHistory num

addToNumHistoryWithChangeHistory : Int -> Model -> Model 
addToNumHistory num modelHistory =
  { model 
    | number = num
    , numberHistory = num :: model.numberHistory
    , changeHistory = getCurrentDate :: model.changeHistory
  }

getCurrentDate : Date

Solution

  • In this specific case, you don't need to have side-effects.

    I've had to add two utility functions to create a functioning example.

    • onInput to handle 'input' event
    • parseInt to retrieve Int from a String

    The rest is a basic Elm Architecture lifecycle as of 0.16

    Please consider this minimal example I made for use with StartApp.Simple:

    import Html exposing (text, input, div, Html, Attribute)
    import Html.Attributes exposing (value)
    import Html.Events exposing (on, targetValue)
    import String
    import Signal exposing (Address)
    import StartApp.Simple as StarApp
    
    
    --Utils
    onInput : Address a -> (String -> a) -> Attribute
    onInput address f =
      on "input" targetValue (\v -> Signal.message address (f v))
    
    
    parseInt : String -> Int
    parseInt string =
      case String.toInt string of
        Ok value ->
          value
    
        Err error ->
          0
    
    
    --Model
    type alias Model =
      { number : Int
      , numberHistory : List Int
      }
    
    
    initModel : Model
    initModel =
      { number = 0
      , numberHistory = []
      }
    
    
    --Update
    
    
    type Action
      = UpdateNumber String
    
    
    update : Action -> Model -> Model
    update action model =
      case action of
        UpdateNumber num -> 
           addToNumHistory (parseInt num) model
    
    
    addToNumHistory : Int -> Model -> Model 
    addToNumHistory num model =
      { model 
        | number = num
        , numberHistory = num :: model.numberHistory
      }
    
    
    --View     
    view : Signal.Address Action -> Model -> Html
    view address model =
      div
        []
        [ input
            {- On every 'input' event,
               grab the value of input field and send to UpdateNumber
            -}
            [ onInput address UpdateNumber, value (toString model.number) ]
            []
        , div [] [ text (toString model.number) ]
        , div
            []
            ( model.numberHistory
              |> List.reverse
              |> List.map (toString)
              |> List.map text
            )
        ]
    
    
    main : Signal Html
    main =
      StarApp.start
        { view = view
        , update = update
        , model = initModel
        }