Applying Maybes When Updating A Model - elm

I want to update my model this way:
updatedModel =
if model.firstChord && model.secondChord then
{ model | firstChord = {}, secondChord = {} }
else
model
the firstChord and the secondChord both are of the type Chord:
type alias Chord =
{ root : Maybe Pitch
, third : Maybe Pitch
, fifth : Maybe Pitch
}
The pitch type looks like:
-- pitch
type alias Pitch = ( PitchName, PitchLevel )
-- pitch name
type alias PitchName = String
-- pitch level
type alias PitchLevel = Int
My initial Model has these fields:
{ firstChord =
{ root = ( "C", 3 )
, third = ( "E", 3 )
, fifth = ( "G", 3 )
}
, secondChord =
{ root = ( "F", 3 )
, third = ( "A", 3 )
, fifth = ( "C", 4 )
}
I like to have optional pitch values.
How can I update my model giving it a value OR nothing?
Thanks.

Not quite sure what are you looking for. I guest you would like to have a Maybe Chord like this.
type Pitch =
Pitch String Int
type alias Chord =
{ root: Maybe Pitch
, third: Maybe Pitch
, fifth: Maybe Pitch
}
type alias Model =
{ firstChord: Maybe Chord
, secondChord: Maybe Chord
}
init: Model
init =
{ firstChord =
{ root = Pitch "C" 3
, third = Pitch "E" 3
, fifth = Pitch "G" 3
}
, secondChord =
{ root = Pitch "F" 3
, third = Pitch "A" 3
, fifth = Pitch "C" 4
}
}
update: Model -> Model
update model =
case (model.firstChord, model.secondChord) of
(Just first, Just second) ->
{ model | firstChord = Nothing, secondChord = Nothing}
_ ->
model

When you have a Maybe a type, such as Maybe Pitch you have two ways to set its value: Nothing or Just a. So instead of this:
{ firstChord =
{ root = ( "C", 3 )
, third = ( "E", 3 )
, fifth = ( "G", 3 )
}
, secondChord =
{ root = ( "F", 3 )
, third = ( "A", 3 )
, fifth = ( "C", 4 )
}
...you need to do this:
{ firstChord =
{ root = Just ( "C", 3 )
, third = Just ( "E", 3 )
, fifth = Just ( "G", 3 )
}
, secondChord =
{ root = Just ( "F", 3 )
, third = Just ( "A", 3 )
, fifth = Just ( "C", 4 )
}
Of course, you then use Nothing so indicate no value:
firstChord =
{ root = Just ( "C", 3 )
, third = Just ( "E", 3 )
, fifth = Nothing
}

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.

Same row height for all table columns using elm-ui

I cannot figure out how to obtain the same row height for every column when using table or indexedTable in elm-ui. Is this possible (without setting a fixed height) or should I resort to implementing my own table with row and column?
The following ellie illustrates the issue.
This is the code used to build the table
bgcolor idx =
(if modBy 2 idx == 0 then
gray
else
white
)
|> Background.color
view model =
indexedTable []
{ data =
[ { f1 = "f11", f2 = "f12" }
, { f1 = "f21", f2 = "f22" }
, { f1 = "f31", f2 = "f32" }
, { f1 = "f41", f2 = "f42" }
]
, columns =
[ { header = text "f1"
, width = fill
, view = \idx d -> el [ Font.size 30, bgcolor idx ] <| text d.f1
}
, { header = text "f2"
, width = fill
, view = \idx d -> el [ Font.size 15, bgcolor idx ] <| text d.f2
}
]
}
|> layout []
Thanks in advance.
Adding height fill to each cell's attributes fixes your Ellie example:
, columns =
[ { header = text "f1"
, width = fill
, view =
\idx d ->
el
[ Font.size 30
, bgcolor idx
, height fill -- NEW!!!
]
<|
text d.f1
--
}
, { header = text "f2"
, width = fill
, view =
\idx d ->
el
[ Font.size 15
, bgcolor idx
, height fill -- NEW!!!
]
<|
text d.f2
}
]
Fixed Ellie here.

Check Value in Dict

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.

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

Elm: Fold specific values of multiple lists

games =
[ { id = 1
, points =
[ { player_id = 1, score = 20 }
, { player_id = 2, score = 10 }
, { player_id = 3, score = 0 }
]
}
, { id = 2
, points =
[ { player_id = 1, score = 20 }
, { player_id = 2, score = 5 }
, { player_id = 3, score = 0 }
]
}
, { id = 3
, points =
[ { player_id = 1, score = 20 }
, { player_id = 2, score = 5 }
, { player_id = 3, score = 10 }
]
}
]
I have a list of 'games' records which each have a list of points for each player.
Is it possible to fold each score of each player across each game to display a 'total'.
Something like:
[ { player_id = 1, score = 60 }
, { player_id = 2, score = 20 }
, { player_id = 3, score = 10 }
]
Thanks in advance.
You need a double fold, where the key code is
main : Html msg
main =
let
go { points } acc =
let
goInner { player_id, score } accInner =
Dict.update player_id (updater score) accInner
in
List.foldl goInner acc points
in
List.foldl go Dict.empty games
|> toString
|> text
updater : Int -> Maybe Int -> Maybe Int
updater score existingVal =
existingVal
|> Maybe.withDefault 0
|> (+) score
|> Just
See [https://ellie-app.com/gq8VFfS8Ja1/0](this ellie)
This gets you the answer you want albeit in a slightly different format