Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify current list by adding an element - Haskell 101

I'd like to add an element on the "movies" list of a data type Director variable called billy.

type Name  = String
type Movie = String
data Director = Director {name:: Name, movies::[Movie]}
    deriving (Show)
let billy = Director "Billy J." ["Good movie 1"]

--addMovieToDirector :: Movie -> Director -> Director
addMovieToDirector m (Director n ms) = Director n (m:ms)

The problem is previous function doesn't update billy's list of movies, it creates a new Director with the desired list (the changes are not stored on billy). How can I operate on billy's list without creating another Director? I understand, that Haskell works with constants, but then should I create a different 'billy' "variable" every time I modify the list?

Thanks!

like image 420
mf295 Avatar asked Mar 08 '23 15:03

mf295


1 Answers

What you would like to do can be described as "in-place modification", or "using mutable data".

There are ways for Haskell to do this. Since in-place modification of anything almost always considered as a "side-effect", such things can only be done in the IO monad, or with dirty tricks like unsafePerformIO.

These are somewhat advanced topics, and at a beginner level it is arguably beneficial to think about Haskell values as being totally immutable.

So yes, you can't modify variables. Actually there are no "variables" at all.

Think about billy as a name for a value, not a variable.

All a function can do in Haskell is to take arguments, and calculate some result without any side effects.

This is probably the biggest mental barrier for people coming from imperative languages: "how should I work with data if I can't modify it"?

The answer is: you should structure your program like giant assembly line: raw materials (raw data, initial parameters, etc.) are put on the line at the beginning (the first function you call), and each workstation (function) does something useful (returns a value), consuming the result of the previous workstation. At the end, something valuable might fall off the line.

What I described is simple function composition: if you need to do c task after b, after a, on a value x, then you can write it as (c . b . a) x, or c (b (a x)) or rather c $ b $ a x.

This way, you can write programs without ever changing anything explicitly, and only describing how to create new things out of old ones.

This sounds awfully inefficient, and indeed, there are some performance implications of functional programming (let alone laziness). However the compiler is smart enough to figure out a whole lot thing about programs written in Haskell, and optimize it in certain ways.

I hope it'll all make sense soon. :)

Oh, and welcome to Haskell. ;)

like image 170
netom Avatar answered Mar 17 '23 11:03

netom