I am trying to pick F# again and I have a case where I find it very difficult to deal with immutability.
In most cases I find immutability very nice. However, I find it very hard to deal with nested collections.
I would like to write a single user GUI program.
For simplicity let’s say we have the model:
type Employee =
{
Name : string
}
type Company =
{
Name : string
Employees : Employee list
}
If I modify an existing Employee with
let myNewEmployee = { myEmployee with Name = "John Smith" }
I get a new Employee and that is fine. However, here comes the chain of problems:
I need to remove the old myEmployee and add myNewEmployee to the
Company’s Employees list.
That provokes a mutation in the list with yields a new list.
That forces me to create a new Company record in order to inject the new collection, having to rebuild entire Company list I have.
In other words, changing an employee’s name, makes me rebuild the entire data structure.
Every time I am stumped, I have found that F# has a different and creative way of doing things.
I assume that it is my ignorance on not knowing how to deal with this situation in a functional way, please enlighten me ;)
Should I be using other F# libraries, like F# Data ?
TIA,
David
I think the answer depends partly on the larger context - such as how is the user interface of your application implemented. You are right that modifying one name in a company requires you to produce a new list and a new company record. That is not too bad if you do it in a single call to List.map though.
To make the sample easier, I added ID of type int to each emplyee:
let updateName id name company =
let newEmployees = company.Employees |> List.map (fun emp ->
if emp.ID = id then { emp with Name = name } else emp)
{ company with Employees = newEmployees }
If you are using something like the Elm architecture, then this is probably a reasonable way to go.
In some cases, you can do a more clever thing (but it depends on your scenario). For example, you could create a new type to represent a company with a list of updates that have been applied to it:
type Update =
| Rename of id:int * newName:string
type UpdatedCompany =
{ Company : Company
Updates : Update list }
Now changing a name is just a matter of appending a new Rename update to the list of Updates. Of course, once you need to display the final Company, you will need to iterate over all the employees (as above) and apply the updates. However, if you do a lot of updates before you need to get a new final Company value, this might be a nice trick.
The functional-first F# style means that you keep your functions pure by default i the core of your program and moving the necessary side-effects towards the edge of your program.
I need to remove the old myEmployee and add myNewEmployee to the Company’s Employees list.
Do you really need to do this? I encourage you to think about this chain going in the opposite direction. Why do you need this new list? What effect does that ultimately have on the outside world? Maybe the complete list can be built up in one pass by restructuring your code to a functional style. Maybe you are responding to user input and it's fine to build a new list every time. Maybe it would be better to use a different data structure like a Map (immutable dictionary) with the employee ID as the key.
Long entry with no clear answers but some ideas on how to deal with nested immutable data
As the OP noted, when discussing immutability an area that is ignored how to update nested properties. While this is trivial in mutable structure (just navigate there and update the property) with immutable structures one need to navigate there, create a copy with the updated property and then recreate all parents.
Luckily people have been thinking about this already and the functional pattern to address this is called Lenses or Prisms.
Lenses have a reputation of being somewhat difficult.
But that IMO is because in Haskell they talk about polymorphic lenses which can be defined like this:
type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t) // Que?
Braver souls than me have implemented polymorphic lenses in F# (which has a more simplistic type system than Haskell): http://www.fssnip.net/7Pk
(The polymorphic lens implementation in F# is provided AFAIK by the guy behind Hopac. He's pretty decent I say)
Polymorphic lenses are cool but if you remove the polymorphic bit lenses become much simpler to understand and still very usable.
Basically a lens is a pair of a getter and a setter function. It could look like this in F#:
type Lens<'T, 'U> = ('T -> 'U)*('T -> 'U -> 'T)
Given a value the getter get a property of that value. Given a value and property value the setter creates a new copy of the value with the property updated.
It can be thought of as a functional composable properties remotely comparable to .NET properties.
Given that your example (and many real-world things) deals with maps and lists Prisms are typically more usable. Here is one proposal:
type [<Struct>] Prism<'T, 'U> = Prism of ('T -> 'U option)*('T -> 'U -> 'T)
The only difference here is that the getter might return None if the property don't exists, for example if the employee don't exist in the list.
For a prism we define the operator >-> which combines a two prisms into a new one that let's you get the focused property as well as updating it like so:
let p = PropertyA >-> PropertyB >-> Property C
// Updates the nested property c in b in a and returns a new instance
let newA = a |> set p c
Let's see how this could look for the example in OPs post.
type Company =
{
Name : string
Employees : Map<EmployeeNo, Employee>
}
// Define Prisms for properties of Company
static member _Name : Prism<Company, _> = prism' (fun t v -> { t with Name = v }) (fun t -> t.Name |> Some)
static member _Employees : Prism<Company, _> = prism' (fun t v -> { t with Employees = v }) (fun t -> t.Employees |> Some)
Unfortunately there is a bit of boiler-plate code surrounding prisms, but that can be mitigated with code-gen tools and possibly even type-providers.
We define Employee in a similar manner and we can start defining functions that allows us manipulating the nested immutable structure.
// Uses Prisms to update the email
let updateEmail company employeeNo newEmail =
company
// The path to the Employee email
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Email) newEmail
Prisms are chainable useful when updating more than one property.
// Uses Prisms to update the position and salary
let updatePosition company employeeNo newPosition newSalary =
company
// The path to the Employee position
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Position) newPosition
// The path to the Employee salary
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Salary ) newSalary
While the example above works it's inefficient to construct two Company objects and throw away the first. Better would be to navigate to the correct Employee and update it before updating the Company object.
// Uses Prisms to update the position and salary
// Does so in a more efficient manner
let updatePosition' company employeeNo newPosition newSalary =
// The problem with updatePosition above is that it constructs a new company
// object with position updated and then another one with the salary updated
// A faster approach is to navigate to the employee and once found
// update both the position and the salary
// Updates an employee position & salary
let updater = function
| None -> None
| Some e -> { e with Position = newPosition; Salary = newSalary} |> Some
company
// The path to the employee
|> update (Company._Employees >-> lookup employeeNo) updater
In conclusion; the implementation given here is intended to be a starting point for perhaps a different way of thinking on how to work with nested immutable structures. There are some issues with the implementation (like knowing if and why an update failed). This is solvable but I didn't want to pollute the idea with lots of worries.
Hopefully you found it interesting.
Full sample code:
// A Prism consists of two parts
// a getter that gets a property of a value (might return None)
// a setter that sets a property of a value (returns a new instance)
type [<Struct>] Prism<'T, 'U> = Prism of ('T -> 'U option)*('T -> 'U -> 'T)
module Prism =
let inline prism g s = Prism (g, s)
let inline prism' s g = Prism (g, s)
// join joins two Prisms into a new Prism, this is how we navigate nested structures
// Note: Creates in addition to a nested getter also a nested setter so a Prism
// allows both getting and setting of nested properties
let inline join (Prism (tg, ts)) (Prism (ug, us)) =
let getter t =
match tg t with
| None -> None
| Some tv -> ug tv
let setter t v =
match tg t with
| None -> t
| Some tv -> ts t (us tv v)
prism getter setter
// Prism that allows us to navigate Maps
let inline lookup key =
let getter m = Map.tryFind key m
let setter m v = Map.add key v m
prism getter setter
// Given a Prism and a value returns the nested property pointed out by the prism
let get (Prism (tg, _)) t = tg t
// Given a Prism and a value sets the nested property pointed out by the prism
let set (Prism (_, ts)) v t = ts t v
// Given a Prism and a value allows an update function to see the nested property
// and return update it
let update (Prism (tg, ts)) u t =
match u (tg t) with
| None -> t
| Some tv -> ts t tv
type Prism<'T, 'U> with
static member inline ( >-> ) (t, u) = Prism.join t u
module Demo =
open System
open Prism
// Our Domain Model
type [<Struct>] EmployeeNo = EmployeeNo of int
type Position = Contractor | IndividualContributor | Manager
// So prisms enforces some measure of boiler plating.
// Can be mitigated by code generations and possibly type providers
type Employee =
{
No : EmployeeNo
Name : string
Email : string
Hired : DateTime
Salary : decimal
Position : Position
}
// Define Prisms for properties of Employee
static member _No = prism' (fun t v -> { t with No = v }) (fun t -> t.No |> Some)
static member _Name = prism' (fun t v -> { t with Name = v }) (fun t -> t.Name |> Some)
static member _Email = prism' (fun t v -> { t with Email = v }) (fun t -> t.Email |> Some)
static member _Hired = prism' (fun t v -> { t with Hired = v }) (fun t -> t.Hired |> Some)
static member _Salary = prism' (fun t v -> { t with Salary = v }) (fun t -> t.Salary |> Some)
static member _Position = prism' (fun t v -> { t with Position = v }) (fun t -> t.Position |> Some)
type Company =
{
Name : string
Employees : Map<EmployeeNo, Employee>
}
// Define Prisms for properties of Company
static member _Name : Prism<Company, _> = prism' (fun t v -> { t with Name = v }) (fun t -> t.Name |> Some)
static member _Employees : Prism<Company, _> = prism' (fun t v -> { t with Employees = v }) (fun t -> t.Employees |> Some)
open Prism
// Uses Prisms to update the email
let updateEmail company employeeNo newEmail =
company
// The path to the Employee email
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Email) newEmail
// Uses Prisms to update the position and salary
let updatePosition company employeeNo newPosition newSalary =
company
// The path to the Employee position
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Position) newPosition
// The path to the Employee salary
|> set (Company._Employees >-> lookup employeeNo >-> Employee._Salary ) newSalary
// Uses Prisms to update the position and salary
// Does so in a more efficient manner
let updatePosition' company employeeNo newPosition newSalary =
// The problem with updatePosition above is that it constructs a new company
// object with position updated and then another one with the salary updated
// A faster approach is to navigate to the employee and once found
// update both the position and the salary
// Updates an employee position & salary
let updater = function
| None -> None
| Some e -> { e with Position = newPosition; Salary = newSalary} |> Some
company
// The path to the employee
|> update (Company._Employees >-> lookup employeeNo) updater
let test () =
// The initial state of the company
let company : Company =
let e no name email year month day salary position =
let eno = EmployeeNo no
let e : Employee =
{
No = eno
Name = name
Email = email
Hired = DateTime (year, month, day)
Salary = salary
Position = position
}
eno, e
let es =
[|
e 1 "Bill Gates" "billg#microsoft.com" 1979 1 1 100000M Manager
e 2 "Melinda Gates" "melindag#microsoft.com" 1985 6 6 20000M IndividualContributor
|] |> Map.ofArray
{ Name = "Microsoft"; Employees = es}
// Does some organizational changes of the company
printfn "Initial: %A" company
let company = updateEmail company (EmployeeNo 1) "billg#hotmail.com"
printfn "Changing Bill Gates email: %A" company
let company = updatePosition company (EmployeeNo 2) Manager 200000M
printfn "Promoting Melinda Gates: %A" company
let company = updatePosition' company (EmployeeNo 1) IndividualContributor 10000M
printfn "Demoting Bill Gates: %A" company
Related
Lets say we have a record which defines a person type with the properties name and age:
type person = {name:string ; age:int };;
and initialize a list with different types:
let personlist = [{name="alexander";age=21};{name="benjamin";age=30};{name="claudia";age=21}];;
How can I count the amount of types with a specific age, lets say 21 (alexander and claudia) so that the output in this case would be two?
The most straightforward way would be to combine List.length and List.filter.
List.(personlist |> filter (fun p -> p.age = 21) |> length)
However, this is somewhat less efficient than it could be. We can do it in one pass because we don't really need to build a list of the matching people, and then iterate over that list to find its length.
List.fold_left will let us iterate over personlist, updating the initial value of 0 on each iteration dependent on whether the age field of each record is 21 or not.
List.fold_left (fun i {age; _} -> i + if age = 21 then 1 else 0) 0 personlist
I'm trying to implement a function that adds an element (a type) to a list of this type to an existing created datatype. Since Haskell data variable are immutable, I know that you have to create a new data with the same characteristic as the first one and add onto it, but I can seem to make ghci compile my program and make it do what I'm trying to accomplish.
Here is my code and the function which should add a contact to a list of already existing contact addContact which I'm been trying to work on:
type Model = String
type Serie = String
type SerialNumber = String
type Type= (Model, Serie)
data Car = Car
SerialNumber
Type
deriving (Show, Read)
type PastCars= (Car, ChangeCause)
data ChangeCause = Broken | Contract deriving (Show, Eq, Read)
type Phone = (Extension, Number)
type Number = String
type Extension = String
type Person = (FirstName, LastName)
type FirstName = String
type LastName = String
type Contact = (Person, Phone)
data Owner = Owner Car Phone [PastCars] [Contact]
--Getters
listPastSN [] = []
listPastSN ((p,e):xs) = (serialNumber p, e):listPastSN xs
serialNumber :: Car -> String
serialNumber (Car s _)= s
car :: Owner -> Car
car (Owner c _ _ _ ) = c
phone :: Owner -> Phone
phone (Owner _ p _ _ ) = p
pastCar :: Owner -> [PastCars]
pastCar (Owner _ _ p _ ) = p
contacts :: Owner -> [Contact]
contacts (Owner _ _ _ c) = c
addContact :: FirstName -> LastName -> Extension -> Number -> Owner -> Owner
addContact f l e n ow = Owner car(ow) phone(ow) pastCar(ow) contacts(ow) ++ (Contact ((f, l), (e, n)))
Let's I have these data variable
car1 = Car "X234X" ("Honda", "Civic")
car2 = Car "X233X" ("Mazda", "3")
person1 = Person "Peter" "Mcleod"
owner1 = Owner car1 ("888" , "4144144") [(car2, Broken)] [(person1,("123", "1231231")) ]
I want to be able to add another contact to the list of contact of owner1.
What is the correct way to go about this. SO and LYAH solution proposed around these type of case don't seem to help.
There are multiple issues in your code. The fixed version of the addContact function:
addContact f l e n ow =
Owner (car ow) (phone ow) (pastCar ow) $ (contacts ow) ++ [((f, l), (e, n))]
Contact is not a constructor, it's a type alias.
f a(b) is the same as f a b. So Owner phone(x) is the same Owner phone x, the same applies to the other arguments.
Take a look at the signature of (++) :: [a] -> [a] -> [a]. You are trying, contacts(ow) ++ (Contact ((f, l), (e, n)).
f a b ++ [1,2,3] is the same as (f a b) ++ [1,2,3]. What you wanted is f a (b ++ [1,2,3]) or f a $ b ++ [1,2,3].
I created a list in f# named tickets that contains 10 records called Ticket.The records are all initialized with their specific seat number and empty customer name.
type Ticket = {seat:int; customer:string}
let mutable tickets = [for n in 1..10 -> {Ticket.seat = n; Ticket.customer = ""}]
I want to write a function to book a specific seat in the list(add a customer name to the seat).
How can i edit an item in the list and have other items still retain their value
The functional F# list type is immutable, which means that you cannot change it. The typical way of working with it would be to return a new, modified, copy.
To do that, you can write a function bookSeat that takes list<Ticket> together with number & new name and produces a new list<Ticket> with that one field updated:
let bookSeat seatNo name tickets =
tickets |> List.map (fun ticket ->
if ticket.seat = seatNo then { ticket with customer = name }
else ticket )
bookSeat 3 "Tomas" tickets
Here is a way to use a list of mutable (ref-cells) tickets:
let maxSeats = 10
let tickets : (int * Ticket option) ref list =
[1..maxSeats]
|> List.map (fun s -> ref (s, None) )
let bookSeat seat name =
match List.tryFind (fun r -> let (s,_) = !r in s = seat) tickets with
| Some r ->
r :=
match !r with
| (s, Some ticket) -> (s, Some { ticket with customer = name })
| (s, None) -> (s, Some { seat = s; customer = name })
| None ->
failwith "seat not found"
obvious you can make tickets itself mutable too, if you want to add seats instead of initializing them with all the obvious seats
a better approach(?)
Still I think that this is the wrong way to do it - I think you want a Map:
type Ticket = {seat:int; customer:string}
type Tickets = Map<int, Ticket>
let bookSeat seat name (tickets : Tickets) =
match Map.tryFind seat tickets with
| Some oldTicket ->
tickets
|> Map.remove seat
|> Map.add seat { oldTicket with customer = name }
| None ->
tickets
|> Map.add seat { seat = seat; customer = name }
note that these are all immutable values, so bookSeat will return a new Ticket-reservation-map
hyprid using Dictionary
or you can use a common .net Dictionary and mutate this:
type Ticket = {seat:int; customer:string}
let tickets = System.Collections.Generic.Dictionary<int, Ticket>()
let bookSeat seat name =
match tickets.TryGetValue seat with
| (true, oldTicket) ->
tickets.[seat] <- { oldTicket with customer = name }
| (false, _) ->
tickets.[seat] <- { seat = seat; customer = name }
Here you don't have to pass the Tickets around - they will be mutated in place (but still the Ticket-objects themselves are still immutable)
Note that this right now is not thread-safe so be careful.
I think the most idiomatic option here would be to simply use a string array. Given you know in advance the size and you want to be able to update it, this is the structure that fills both those needs most idiomatically. So,
// create 10-element string array initialized with null
let (tickets : string array) = Array.zeroCreate 10
...
tickets.[3] <- "New Customer"
keep it simple.
Granted this is not "purely-functional" (but any purely functional solutions here just kick the non-pure parts down the road anyway), but if the goal is just to get the job done, this will do it.
I have the following code which creates the database...
type Title = String
type Singer = [String]
type Year = Int
type Fan = String
type Fans = [Fan]
type Film = (Title, Actor, Year, Fans)
type Database = [Film]
filmDatabase :: Database
filmDatabase = [("Wrapped up", ["Olly Murs"], 2014, ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
("Someone Like you", ["Adele"], 2011, ["Bill", "Jo", "Garry", "Kevin", "Olga", "Liz"]),
I then have used the following code to search for A fan and display all the music they like.
fanOfFilms :: Fan -> Film -> Bool
fanOfFilms fan (t, _, _, f)
|elem fan f = True
|otherwise = False
givenUser :: Fan ->[Film]
givenUser fan = filter (fanOfFilms fan) testDatabase
I want to now take this code and make it only display the titles. How do i do this? I have tried using map and tried to use pattern matching but cannot get it to work?!
code I tried
titleOnly :: (t, a, y, f) -> (t, f)
titleOnly (t, _, _, f) = (t, f)`
I then tried linking this to FansFilms but it looks messy and i don't know how to correctly
You can create a function that, given a Film, returns its title:
filmTitle :: Film -> Title
filmTitle (t, _, _, _) = t
And then map this function over the list of Films returned by givenUser.
givenUserTitles :: Fan -> [Title]
givenUserTitles fan = map filmTitle (givenUser fan)
To get the first item in a tuple, use fst. You can get the second item with snd, which is useful because many times you will use ordered pairs as tuples. The most readable way to get the title out of the tuple I think would be:
title :: Film -> Title
title (t,_,_,_) = t
To get the fans,
fans :: Film -> Fans
fans (_,_,_,f) = f
Now what you want to do is match up a fan with all of the titles they are a fan of, correct? This means that you will need to check each film title if the fan is a member of the list of fans. You can do this with the elem function.
Let me know if any of this does or doesn't work!
Using the lens package (not that I'm saying that you should use it), you can use _1, _2 etc ...
Example
("title", "actor", "year", "fans") ^. _4
>>> "fan".
However, in that situtation, you probably should use a record.
Can anyone explain *what is lenses` in terms of OCaml?
I tried to google it, but almost all of them are in Haskell's world.
Just wish some simple demonstrations for it in OCaml's world, like what it is, what it can be used for, etc.
A lens is a pair of functions (getter and setter) that are under a data-structure. It's really that simple. There is currently a library for them,
type ('s,'a) t =
{ get : 's -> 'a;
set : 'a -> 's -> 's; }
An example (using the ocaml library listed above) for a tailor,
type measurements = { inseam : float; }
type person = { name : string; measurements : measurements; }
let lens_person_measurements =
{ get = (fun x -> x.measurements);
set = (fun a x -> {x with measurements = a}); }
let lens_measurements_inseam =
{ get = (fun x -> x.inseam);
set = (fun a x -> {x with inseam = a}); }
let lens_person_inseam =
compose lens_measurements_inseam lens_person_measurements
When composing the lenses together, you can see it as a way to avoid having to write with constantly when dealing with records. You can also see that a ppx to create these lenses would be very helpful. Yaron recently posted on the caml-list they are working on something that would be similar to lens.
An important insight in the van Laarhoven Lens definition(PDF) shows how one function (fmap) of a particular Functor can do these operations (set and get and very helpfully an update function).