Check Value in Dict - elm

Trying to check the value of fruit
fruit =
Dict.fromList
[ ( 1, { fruitIsGood = False } )
, ( 2, { fruitIsGood = False } )
, ( 3, { fruitIsGood = True } )
]
whichFruitIsGood : Dict.Dict number { fruitIsGood : Bool } -> String
whichFruitIsGood fruit =
case get 0 fruit of
Nothing ->
Debug.crash "nothing found"
Just fruit ->
if fruit.fruitIsGood == True then
"Apple"
else
"I hate Fruit"
I don't know how to get at the fruitIsGood prop or whatever you call it in Elm here..

First, Debug.crash "nothing found" won't provide to you any useful functionality, what about returning nothing found string instead.
Then you just need to fix the errors, which the compiler points out. They are mostly about the variables, which are defined multiple times. Let's rename your first function to fruits:
fruits =
Dict.fromList
[ ( 1, { fruitIsGood = False } )
, ( 2, { fruitIsGood = False } )
, ( 3, { fruitIsGood = True } )
]
And a variable in the second function:
whichFruitIsGood : Dict.Dict number { fruitIsGood : Bool } -> String
whichFruitIsGood fruit =
case get 3 fruit of
Nothing ->
"nothing found"
Just foundFruit ->
if foundFruit.fruitIsGood == True then
"Apple"
else
"I hate Fruit"
Then your code will compile and return nothing found as a result.
Here's a small a bit modified ellie-app example, which shows the code in action.

Related

Add element to list on update, together with other changes in a record

I have the following initialModel,
initialModel : Model
initialModel =
{ cards =
[ { url = "Gita.jpg", card = 1, selected = False }
, { url = "Kali.jpg", card = 2, selected = False }
, { url = "Arjuna.jpg", card = 3, selected = False }
, { url = "Krishna.jpg", card = 4, selected = False }
, { url = "Manjusri.jpg", card = 5, selected = False }
, { url = "siddartha.jpg", card = 6, selected = False }
, { url = "bodhidharma2.jpg", card = 7, selected = False }
]
, selectedCards = [ "card1" ]
, activeCard = ""
}
And I have them hooked with onClick,
type Msg
= ClickedCard { url : String, id : String }
| Other
update : Msg -> Model -> Model
update msg model =
case msg of
ClickedCard data ->
{ model
| activeCard = data.id
, selectedCards = selectedCards ++ data.id -- This line is pseudo-code
}
_ ->
model
How can I make that update work? So, in the end, every click on a new card should make it on the selectedCards list.

Include a lambda inside an if..else statement

I have the following function:
fun ValueListItem(
label: String,
value: String,
onClick: (() -> Unit)? = null
) {
}
But calling it like this is not allowed:
var edited = false
ValueListItem(
label = "my label",
value = "some value",
onClick = if (viewmodel.canEdit) { edited = true } else null
)
But calling it like this is allowed:
var edited = false
val onEditDateTime = {
edited = true
}
ValueListItem(
label = "my label",
value = "some value",
onClick = if (viewmodel.canEdit) onEditDateTime else null
)
How can I pass the lambda in a conditional statement rather than having to declare the lambda as an extra construct.
By writing
ValueListItem(
label = "my label",
value = "some value",
onClick = if (viewmodel.canEdit) { edited = true } else null
)
The compiler sees the braces as part of the if-statement syntax.
Simply adding another pair of braces like this should do the trick I think
ValueListItem(
label = "my label",
value = "some value",
onClick = if (viewmodel.canEdit) {{ edited = true }} else null
)

How do you fix Fatal error: index out of range? Swift

I know I have to return some sort of value in my code so it does not keep crashing with this thread error, but I can't figure it out. Please help! Here is the code- `
#IBAction func decideBttn(_ sender: Any) {
// if there is data in more than one Label randomly pick 1 out of 2
if valueLbl1.text?.isEmpty == false && valueLbl2.text?.isEmpty == false
{
var topics = [valueLbl1.text!, valueLbl2.text!]
pickTopic = Int(arc4random_uniform(UInt32(topics.count)))
topics.remove(at: pickTopic)
resultLbl.text = "\(topics[pickTopic])" //Where fatal error occurs
valueLbl1.text = ""
valueLbl2.text = ""
valueLbl3.text = ""
return
}
// if all 3 Labels are used button will randomly pick 1 out of 3
else if valueLbl1.text?.isEmpty == false && valueLbl2.text?.isEmpty == false && valueLbl3.text?.isEmpty == false
{
var topics = [ valueLbl1.text!, valueLbl2.text!, valueLbl3.text!]
pickTopic = Int(arc4random_uniform(UInt32(topics.count)))
topics.remove(at: pickTopic)
resultLbl.text = "\(topics[pickTopic])"
// resetting variable value
valueLbl1.text = ""
valueLbl2.text = ""
valueLbl3.text = ""
return
}

Get List inside List

I have a complex data structure and I had to create this short example for better understanding.
type alias People =
{ name : String
, sex : String
, phones : List Phone
}
type alias Phone =
{ number : String
, isActive : Bool
}
This structure populated:
people = [
{ name = "_me"
, sex = "M"
, phones = [
{ number = "(99) 99 9 9999-9999"
, isActive = True
}]
},
{ name = "_you"
, sex = "M"
, phones = [
{ number = "(11) 11 1 1111-1111"
, isActive = True
},
{ number = "(22) 22 2 2222-2222"
, isActive = False
}]
}]
And I would like to get only the 'phones' from the 'people' list, as in the example below
phones = [
{ number = "(99) 99 9 9999-9999"
, isActive = True
},
{ number = "(11) 11 1 1111-1111"
, isActive = True
},
{ number = "(22) 22 2 2222-2222"
, isActive = False
}]
I've been trying for 3 days, but to no avail.
You can pull out all the phone numbers into a list by mapping over to get the phone number list of a person, then concatenating those phone number lists together:
getPhones : List People -> List Phone
getPhones = List.concat << List.map .phones

Strange error using Type Bool in Record in elm

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) ]
]
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
}