My stupid introduction to Haskell
While I was writing my first small program on Haskell (really simple, but functional webapp) in December 2017 I only knew vaguely what was the style of things, some basic notions about functions, pure functions and so on (I’ve read about a third of LYAH).
An enourmous amount of questions began to appear in my head while I read tutorials and documentation. Here I present some of the questions and the insights I got that solved them. Technically, they may be wrong, but they helped me advance in the matter, so I’m writing them down while I still can – If I keep working with Haskell I’ll probably get to know more and so my new insights will replace the previous ones, and the new ones won’t be useful for total begginers anymore.
Here we go:
- Why do modules have odd names?
- modules are the things you import, like
Data.Time.Clock
orWeb.Scotty
. - packages are the things you install, like ‘time’ or ‘scotty’
- packages can contain any number of modules they like
- a module is just a collection of functions
- a package is just a collection of modules
- a package is just name you choose to associate your collection of modules with when you’re publishing it to Hackage or whatever
- the module names you choose when you’re writing a package can be anything, and these are the names people will have to
import
when they want to use you functions- if you’re from Javascript, Python or anything similar, you’ll expect to be importing/writing the name of the package directly in your code, but in Haskell you’ll actually be writing the name of the module, which may have nothing to do with the name of the package
- people choose things that make sense, like for
aeson
instead ofimport Aeson
you’ll be doingimport Data.Aeson
,import Data.Aeson.Types
etc. why theData
? because they thought it would be nice. dealing with JSON is a form of dealing with data, so be it.- you just have to check the package documentation to see which modules it exposes.
- modules are the things you import, like
- What is
data User = User { name :: Text }
?- a data type definition. means you’ll have a function
User
that will take a Text parameter and output aUser
record or something like that. - you can also have
Animal = Giraffe { color :: Text } | Human { name :: Text }
, so you’ll have two functions, Giraffe and Human, each can take a different set of parameters, but they will both yield an Animal.- then, in the functions that take an Animal parameter you must typematch to see if the animal is a giraffe or a human.
- a data type definition. means you’ll have a function
- What is a monad?
- a monad is a context, an environment.
- when you’re in the context of a monad you can write imperative code.
- you do that when you use the keyword
do
.
- you do that when you use the keyword
- in the context of a monad, all values are prefixed by the monad type,
- thus, in the
IO
monad allText
isIO Text
and so on.
- thus, in the
- some monads have a relationship with others, so values from that monad can be turned into values from another monad and passed between context easily.
- for exampĺe, scotty’s
ActionM
andIO
.ActionM
is just a subtype ofIO
or something like that.
- for exampĺe, scotty’s
- when you write imperative code inside a monad you can do assignments like
varname <- func x y
- in these situations some transformation is done by the
<-
, I believe it is that the pure value returned byfunc
is being transformed into a monad value. so iffunc
returnsText
, now varname is of typeIO Text
(if we’re in the IO monad). - so it will not work (and it can be confusing) if you try to concatenate functions like
varname <- transform $ func x y
, but you can somehow dovarname <- func x y
othervarname <- transform varname
- or you can do other fancy things you’ll get familiar with later, like
varname <- fmap transform $ func x y
- why? I don’t know.
- in these situations some transformation is done by the
- when you’re in the context of a monad you can write imperative code.
- a monad is a context, an environment.
- How do I deal with Maybe, Either or other crazy stuff?
“ok, I understand what is a Maybe: it is a value that could be something or nothing. but how do I use that in my program?”
- you don’t! you turn it into other thing. for example, you use fromMaybe, a function that takes a default value and that’s it. if your
Maybe
isJust x
you getx
, if it isNothing
you get the default value.- using only that function you can already do whatever there is to be done with Maybes.
- you can also manipulate the values inside the
Maybe
, for example:- if you have a
Maybe Person
andPerson
has aname
which isText
, you can apply a function that turnsMaybe Person
intoMaybe Text
AND ONLY THEN you apply the default value (which would be something like the"unnamed"
) and take the name from inside theMaybe
.
- if you have a
- basically these things (
Maybe
,Either
,IO
also!) are just tags. they tag the value, and you can do things with the values inside them, or you can remove the values.- besides the example above with Maybes and the
fromMaybe
function, you can also remove the values by usingcase
– for example:case x of
Left error -> error
Right success -> success
case y of
Nothing -> "nothing!"
Just value -> value
- (in some cases I believe you can’t remove the values, but in these cases you’ll also don’t need to)
- for example, for values tagged with the IO, you can’t remove the IO and turn these values into pure values, but you don’t need that, you can just take the value from the outside world, so it’s a IO Text, apply functions that modify that value inside IO, then output the result to the user – this is enough to make a complete program, any complete program.
- besides the example above with Maybes and the
- you don’t! you turn it into other thing. for example, you use fromMaybe, a function that takes a default value and that’s it. if your
- JSON and interfaces (or instances?)
- using Aeson is easy, you just have to implement the
ToJSON
andFromJSON
interfaces. - “interface” is not the correct name, but I don’t care.
ToJSON
, for example, requires a function namedtoJSON
, so you doinstance ToJSON YourType where
toJSON (YourType your type values) = object []
… etc.
- I believe lots of things require interface implementation like this and it can be confusing, but once you know the mystery of implementing functions for interfaces everything is solved.
FromJSON
is a little less intuitive at the beggining, and I don’t know if I did it correctly, but it is working here. Anyway, if you’re trying to do that, I can only tell you to follow the types, copy examples from other places on the internet and don’t care about the meaning of symbols.
- using Aeson is easy, you just have to implement the