Reputation: 4906
import Control.Lens
import Data.List (filter)
import Data.Time
import Data.Text
data Vehicle = Vehicle
{ _name :: Text
, _admissionDate :: Day
, _vehicleId :: Int
, _refuels :: [Refuel]
}
makeLenses ''Vehicle
data Refuel = Refuel
{ distance :: Int
, volume :: Double
, pricePerUnit :: Double
}
addRefuel :: Refuel -> Vehicle -> Vehicle
addRefuel refuel = refuels <>~ [refuel]
addRefuelToVehicle :: Int -> refuel -> [Vehicle] -> [Vehicle]
addRefuelToVehicle vehicleId refuel vehicles =
case vehicle of
-- Not actual implementation
Nothing -> error "Vehicle not found"
Just v ->
let
vehicle = addRefuel v refuel
-- Add everything that is not the vehicle and add modified vehicle
filter (\v' -> v' ˆ. vehicleId /= vehicleId) vehicles ++ [vehicle]
where
vehicle = find (\v -> v ^. vehicleId == vehicleId) vehicles
vehicles =
[ Vehicle { _name = "Car 1", _admissionDate = fromGregorian 2006 4 6, _vehicleId = 1, _refuels = []
, Vehicle { _name = "Car 2", _admissionDate = fromGregorian 2013 7 22, _vehicleId = 2, _refuels = []
]
In this example I want to add a Refuel
to the _refuels
list of the vehicle with _vehicleId = 1
. In an object-oriented language, I would solve it like this:
// Ignoring the fact that it may be null
vehicles
.find { it._vehicleId == 1 }
._refuels
.append(refuel)
How would you go around and solve this in Haskell?
Upvotes: 1
Views: 65
Reputation: 531165
Without using lenses, you would write a function like
addRefuel :: ID -- vehicle id
-> Refuel -- refueling data
-> [Vehicle] -- list of vehicles, one of which you want to update
-> [Vehicle] -- list of vehicles after the update
addRefuel _ _ [] = []
addRefuel vid r (v:vs) | _vehicleId v == vid = v { _refuel = r : _refuel v} : vs
| otherwise = v : addRefuel vid r vs
You can call this on your vehicles
list, but then you pass the return value to whatever code will use your updated list.
Upvotes: 1
Reputation: 120711
You can do it very similar to your OO code:
vehicles & traverse
. filtered ((==1) . _vehicleId)
. refuels
<>~ [refuel]
N.B.: this will update all vehicles with matching IDs, and if there's none it'll just silently do nothing. Maybe not the behavious you want.
Upvotes: 3