0
votes

i have the following type User:

type alias User =
{ id : Int
, name : String
, age : Maybe Int
, deleted : Bool
}

User is a type used in my Model:

type alias Model =
{ users : List User
, name : String
, age : String
, message : String
}

When I iterate over "List User" using List.map like this...

Delete id ->
        let
            newUserList =
                List.map
                    (\user ->
                      if user.id == id then
                          { user | deleted = True }
                      else
                          user
                    )
                    model.users
        in
            ( { model | users = newUserList }, Cmd.none )

... the Compiler tells me:

The 2nd argument to function `map` is causing a mismatch.

                 List.map
                     (\user ->
                         if user.id == id then
                             { user | deleted = True }
                         else
                             user
                     )
                    model.users

Function `map` is expecting the 2nd argument to be:

List { a | id : Int, name : String }

But it is:

List (Bool -> User)

That is pretty strange for me. Why does my map function change the Type User...? I do not change it, I just iterate over, map each user and if I found the right one, by its id, I change deleted value to True...

I am a bit confused... Can anyone help?

kind regards :)

UPDATE: It does not seem to me a problem of the List.map function but of the type alias User declaration. As soon as I add another value this breaks...

Here is the whole code for it. It is kept pretty simple. Note: As soon as you uncomment the Users property "deleted" the compiler throws an error

    module Main exposing (..)

    import Html exposing (Html, text, h1, div, img, input, form, ul, li, i, hr, br)
    import Html.Attributes exposing (..)
    import Html.Events exposing (..)
    import Html.App as App
    import String
    import Random


    --import Debug
    --import Uuid


    main : Program Never
    main =
        App.program
            { init = init
            , view = view
            , update = update
            , subscriptions = subscriptions
            }



    -- SUBSCRIPTIONS


    subscriptions : Model -> Sub Msg
    subscriptions model =
        Sub.none



    --MODEL


    type alias Model =
        { users : List User
        , name : String
        , age : String
        , message : String
        }


    type alias User =
        { id : Int
        , name : String
        , age :
            Maybe Int
            --    , deleted : Bool
        }


    init : ( Model, Cmd Msg )
    init =
        ( initModel, Cmd.none )


    initModel : Model
    initModel =
        { users = []
        , name = ""
        , age = ""
        , message = ""
        }



    --UPDATE


    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
            InsertName username ->
                ( { model | name = username }, Cmd.none )

            InsertAge age ->
                let
                    newAge =
                        case String.toInt age of
                            Err err ->
                                ""

                            Ok value ->
                                toString value

                    newMessage =
                        case String.toInt age of
                            Err err ->
                                "Age must be a number!"

                            Ok int ->
                                ""
                in
                    ( { model | age = newAge, message = newMessage }, Cmd.none )

            InitNewUser ->
                ( model, Random.generate AddNewUser (Random.int 1 9999) )

            AddNewUser randomId ->
                if String.isEmpty model.name then
                    ( { model | message = "Please give a name" }, Cmd.none )
                else
                    let
                        ageAsInt =
                            case String.toInt model.age of
                                Err err ->
                                    Nothing

                                Ok int ->
                                    Just int

                        newUser =
                            User randomId model.name ageAsInt

                        newUserList =
                            newUser :: model.users
                    in
                        ( { model | users = newUserList, name = "", age = "" }, Cmd.none )

            Delete id ->
                let
                    newUserList =
                        List.map
                            (\user ->
                                if user.id == id then
                                    { user | name = "--deleted--" }
                                else
                                    user
                            )
                            model.users
                in
                    ( { model | users = newUserList }, Cmd.none )



    --VIEW


    type Msg
        = InsertName String
        | InsertAge String
        | AddNewUser Int
        | InitNewUser
        | Delete Int


    userListView : Model -> Html Msg
    userListView model =
        let
            newList =
                List.filter (\user -> (user.name /= "--deleted--")) model.users
        in
            newList
                |> List.sortBy .name
                |> List.map userView
                |> ul []


    userView : User -> Html Msg
    userView user =
        let
            ageAsString =
                case user.age of
                    Just val ->
                        val |> toString

                    Nothing ->
                        "-"
        in
            li []
                [ div [] [ text ("ID: " ++ toString user.id) ]
                , div [] [ text ("Name: " ++ user.name) ]
                , div [] [ text ("Age: " ++ ageAsString) ]
                , input [ type' "button", value "Delete", onClick (Delete user.id) ] []
                ]


    view : Model -> Html Msg
    view model =
        div [ class "wrapper" ]
            [ h1 [] [ text ("We have " ++ toString (List.length model.users) ++ " Users") ]
            , Html.form []
                [ input [ type' "text", onInput InsertName, placeholder "Name", value model.name ] []
                , input [ type' "text", onInput InsertAge, placeholder "Age", value model.age ] []
                , input [ type' "button", onClick InitNewUser, value "Add new user" ] []
                ]
            , div [] [ text model.message ]
            , userListView model
            , hr [] []
            , div [] [ text (toString model) ]
            ]
1
I suggest you to remove elm-stuff and re-build them all. May be some kind of caching problem.Tosh
no, sorry, did remove all stuff and reinstalled packages... same problem... But thanks :)marschro
What does the code look like that's creating the User values? The list containing functions (Bool -> User) point to the user values being the problem - my bet is something with the Maybe Int is going wrong.d11n

1 Answers

1
votes

The problem is this part of the AddNewUser message:

newUser =
    User randomId model.name ageAsInt

It is missing False as the forth argument when you use the deleted property.

If you do not include it, the User function will return a partially applied function that still needs a Bool to return a proper user. The compiler seems to get thrown off by this even though all your types and functions have proper annotations.

Another way that leads to a better error message would be to define newUser like this:

newUser =
    { id = randomId
    , name = model.name
    , age = ageAsInt
    , deleted = False
    }