How to map numbers of a list?


#1

I have a list containing strings(players) and integers(strengths). I achieved to output the players with , div [] ( if model.activatedOutput then (List.map (\{ player} -> div [] [ text player ]) model.teams) else [] ) Now I also wanted to output the strength value stored in this record/list. But Get an argument error.

The 2nd argument to map is not what I expect:

130| , div [] ( if model.activatedOutput then (List.map ({ strength} -> div [] [ text strength ]) model.teams) else [] ) ^^^^^^^^^^^ The value at .teams is a:

List { activated : Bool, player : String, strength : Int }
But map needs the 2nd argument to be:

List { activated : Bool, player : String, strength : String }

I thought the error was due to the fact that strength has to be a string to map. But I had it converted into a String in the view. So I don’t really get where this error comes from.

Here are some other parts of my code(The line actually causing the error is the last line in the code below):

-- MODEL
type alias Player =
  { player : String
  , strength : Int
  , activated : Bool
  }


type alias Model =
  { content : String
  , teams : List Player
  , currentPlayer : String
  , currentStrength : Int
  , activatedOutput : Bool
  }

-- UPDATE
...
 Add ->
      { model | teams = ({player = model.currentPlayer, strength = model.currentStrength, activated = True} :: model.teams), currentPlayer = "", currentStrength = 0 } 



init : Model
init =
  { content = ""
  , teams = []
  , currentPlayer = ""
  , currentStrength = 0
  , activatedOutput = False

   }
-- VIEW

view : Model -> Html Msg
view model =
  let
    playername = "🏅 Player " ++ String.fromInt (List.length model.teams + 1)
  in
  div []
    [ h1 [style "font-family" "impact"] [ text "Team Creator" ]
    , p [style "font-family" "sans-serif", style "font-size" "15px", style "color" "grey"] [ text "With the Team Creator you can create teams. Insert information about the name and the strength(1-5) of every player and finally how many teams you want to have created by the Team Creator" ]
    ,  h2 [style "font-family" "impact"] [ text "Number of Teams:" ]
    , input [ placeholder  "Number", style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#32db64", value (String.fromInt model.currentNumber), onInput ChangeNumber] []
    ,  h2 [style "font-family" "impact"] [ text "Players per Team:" ]
    , input [ placeholder  "Playernumber", style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#32db64", value (String.fromInt model.currentPlayernumber), onInput ChangePlayernumber] []
    ,  h2 [style "font-family" "impact"] [ text "Name and Strength:" ]
    , div[] [ input [placeholder  playername, style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#488aff", value model.currentPlayer, onInput ChangePlayer] [] ]
    , input [ placeholder  "💪🏼 Strength", style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#4286F5", value (String.fromInt model.currentStrength), onInput ChangeStrength] []
    , div [] [ button [ style "background-color" "#66cc81", style "color" "white", style "margin-top" "20px", style "width" "300px", style "border-radius" "25px", style "height" "40px", style "font-size" "20px", style "margin-right" "70px", onClick Add] [ text "+ADD Player" ] ]
    , div [] [ button [ style "background-color" "#4286F5", style "color" "white", style "margin-top" "10px", style "width" "300px", style "border-radius" "25px", style "height" "40px", style "font-size" "20px", style "margin-right" "70px", onClick Submit] [ text "SUBMIT!" ] ]
    ,  h2 [style "font-family" "impact", style "margin-top" "20px"] [ text "Generated Teams:" ]
    , div [] ( if model.activatedOutput then (List.map (\{ player} -> div [] [ text player ]) model.teams) else [] )
    , div [] ( if model.activatedOutput then (List.map (\{ strength} -> div [] [ text strength ]) model.teams) else [] )
    ]

#2

You need text (String.fromInt strength) in your view.
You are giving an Int to function that expects a String…

You would have seen this immidiatly if you had some Type annotations…
I like to break everything up into small top level functions, then the types will tell you exactly where the error is…
Now it complains in the map function, but with annotations it would have been on the text function that receives an int… and the error message would be : I expected String but got Int… :slight_smile:

Also a hot tip: Try mdgriffith/elm-ui, you will Never go back to normal Html :slight_smile:

Here is an idea of what I’m talking about, I started with a few of them:

view : Model -> Html Msg
view model =
  let
    playername = "🏅 Player " ++ String.fromInt (List.length model.teams + 1)
  in
  div []
    [ heading
    , description
    ,  h2 [style "font-family" "impact"] [ text "Number of Teams:" ]
    , currentNumberInput model.currentNumber
    ,  h2 [style "font-family" "impact"] [ text "Players per Team:" ]
    , ,  h2 [style "font-family" "impact"] [ text "Name and Strength:" ]
    , div[] [ input [placeholder  playername, style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#488aff", value model.currentPlayer, onInput ChangePlayer] [] ]
    , input [ placeholder  "💪🏼 Strength", style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#4286F5", value (String.fromInt model.currentStrength), onInput ChangeStrength] []
    , div [] [ button [ style "background-color" "#66cc81", style "color" "white", style "margin-top" "20px", style "width" "300px", style "border-radius" "25px", style "height" "40px", style "font-size" "20px", style "margin-right" "70px", onClick Add] [ text "+ADD Player" ] ]
    , div [] [ button [ style "background-color" "#4286F5", style "color" "white", style "margin-top" "10px", style "width" "300px", style "border-radius" "25px", style "height" "40px", style "font-size" "20px", style "margin-right" "70px", onClick Submit] [ text "SUBMIT!" ] ]
    ,  h2 [style "font-family" "impact", style "margin-top" "20px"] [ text "Generated Teams:" ]
    , div [] ( if model.activatedOutput then (List.map (\{ player} -> div [] [ text player ]) model.teams) else [] )
    , div [] ( if model.activatedOutput then (List.map (\{ strength} -> div [] [ text strength ]) model.teams) else [] )
    ]


heading : Html msg 
heading = 
    h1 [style "font-family" "impact"] [ text "Team Creator" ]

description : Html msg
description =
    p [style "font-family" "sans-serif"
    , style "font-size" "15px"
    , style "color" "grey"] 
    [ text "With the Team Creator you can create teams. Insert information about the name and the strength(1-5) of every player and finally how many teams you want to have created by the Team Creator" ]
    
currentNumberInput : Int -> Html Msg
currentNumberInput currentInput =
    input [ placeholder  "Number"
    , style "width" "300px"
    , style "height" "30px"
    , style "font-size" "25px"
    , style "color"  "#32db64"
    , value (String.fromInt currentNumber)
    , onInput ChangeNumber] []

currentPlanerNumberInput : Int -> Html Msg
currentPlanerNumberInput currentPayerNumber =
input [ placeholder  "Playernumber"
, style "width" "300px", style "height" "30px", style "font-size" "25px", style "color"  "#32db64", value (String.fromInt currentPlayernumber), onInput ChangePlayernumber] []

#3

Ok @Atlewee but I already have transformed it into a String with:

, input [ placeholder "💪🏼 Strength", ..., value (String.fromInt model.currentStrength), onInput ChangeStrength] []

Then I tried something like:

, div [] ( if model.activatedOutput then (List.map (\{ String.fromInt strength} -> div [] [ text strength ]) model.teams) else [] )

But obviously something doesnt work with the brackets, I dont really get the Syntax.


#4

Try this:

div [] ( if model.activatedOutput then 
  (List.map (\{strength}-> div [] [ text (String.fromInt strength) ]) model.teams) else [] )

the value you receive in your map function is a player, but when using brackets you extract only that field… like {strenght} converts player to player.strenght.
Doing String.fromInt inside this operation is not allowed, so you do it afterwards.

But there is mch clearer way to understand what is happening in your code…
Plus the compiler will lead you straigt to your problem, loud and clear… And you will se instantly where the error is :slight_smile:
Try something like this: It uses more vertical space, but its really delightful to work with, and come back to a few months later…

renderPlayer : Player -> Html msg
renderPlayer player = 
  div [] 
    [ text "Player name:"
    , text player.player
    , text "Player Strenght:"
    , text (String.fromInt player.strength)
    ]

renderTeams : List Player -> Html msg 
renderTeams teams =
  div [] (List.map renderPlayer teams)


if model.activatedOutput then 
  renderTeams model.teams
else
  div [] []

#5

Hello Colin,
@Atlewee already gave the right answer, I just wanted to offer some advice as you seem to be new around here.

Using Ellie instead of directly pasting code into the answer gives you some benefits:

  • It has elm format
  • you can run examples in the browser
  • you can even save code that does not compile
  • you can share the link on several platforms

This makes it easier for folks to read your code and help you out.
Even though elm format does not enforce it, you can easily break long lists into multiple lines. Just enter one linebreak and hit format. This way your view functions are easier to read:
https://ellie-app.com/4Q6rHDqzP8qa1

In case you have to head about it, the https://elmlang.slack.com is also very active and can often give you answers even faster.

Welcome to the elm community!


closed #6

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