Reputation: 47
I have a list of tuples that contain variables and their values. I want to update the value of one specific variable and return the updated list. I guess it should be something like:
updateValue variable val (x:xs)
| fst x == variable = snd x = val (update the value somehow)
| otherwise update variable val xs
I have read that there is no such thing like reassign a value in Haskell and also I do not understand how can I update the value and return a new list.
Update: if I have [(variable, 1), (variable,2), (variable, 4), (variable2, 2)]
and I update the variable to 5, I will get [(variable, 5), (variable, 5), (variable, 5), (variable2, 2)]
, instead of just [(variable, 5), (variable2, 2)]
. Is there a way to make this function this way?
Upvotes: 1
Views: 351
Reputation: 120711
What we mean by “changing” a value is normally, returning a modified copy. In your case, you would pass the original list as the argument to your function and get the modified one back as the result. The original list stays intact (but if it's not used anywhere else, the garbage collector will quickly delete it).
type VarId = String
updateValue :: VarId -> a -> [(VarId,a)] -> [(VarId,a)]
updateValue variable val ((v,x):xs)
| v==variable = (v,val) : updateValue variable val xs
| otherwise = (v,x) : updateValue variable val xs
I highlighted the parts where you also pass back the unchanged data.
Alternatively – Haskell does have mutable variables, just you need to be explicit and work in a suitable monad. In this case, you could use mutable vectors in the ST monad:
import qualified Data.Vector.Mutable as VM
import Control.Monad.ST
updateValue :: VarId -> a -> VM.MVector s (VarId, a) -> ST s ()
updateValue variable val xs = go 0
where go i
| i >= VM.length xs = return ()
| otherwise = do
VM.modify xs
(\(v,x) -> (v, if v==variable then val else x))
i
go $ i+1
Upvotes: 3