Why Nostr? What is Njump?
2024-01-14 14:55:28

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 or Web.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 of import Aeson you'll be doing import Data.Aeson, import Data.Aeson.Types etc. why the Data? 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.
  • 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 a User 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.
  • 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.
      • in the context of a monad, all values are prefixed by the monad type,
        • thus, in the IO monad all Text is IO Text and so on.
      • 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 and IO. ActionM is just a subtype of IO or something like that.
      • 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 by func is being transformed into a monad value. so if func returns Text, now varname is of type IO 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 do
          • varname <- 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.
  • 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 is Just x you get x, if it is Nothing 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 and Person has a name which is Text, you can apply a function that turns Maybe Person into Maybe Text AND ONLY THEN you apply the default value (which would be something like the "unnamed") and take the name from inside the Maybe.
    • 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 using case -- 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.
  • JSON and interfaces (or instances?)
    • using Aeson is easy, you just have to implement the ToJSON and FromJSON interfaces.
    • "interface" is not the correct name, but I don't care.
    • ToJSON, for example, requires a function named toJSON, so you do
      • instance 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.

See also

  • Haskell Monoids
Author Public Key
npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6