Giter Site home page Giter Site logo

haskell_examples's Introduction

Algebras

Writing Typeclasses

To write a typeclass instance for a datatype, run :i <Typeclass> to find its kindedness:

class Semigroup a where
class Functor (f :: * -> *) where

Semigroup expects a concrete type constructor whereas functor expects one with a type parameter. If I'm writing a semigroup instance for Maybe, a type constructor of kind * -> *, I must supply the type parameter in the instance header. And I might have to constrain the parameter, depending on what I want to do with it.

Once I have the header done, it's just a matter of defining the required functions for all possible combinations of data constructors.

General Pattern

At Haskell's core are several mathematical structures. They are defined via typeclass. They are, in order of increasing strength:

  • semigroup
  • monoid
  • functor
  • applicative
  • monad

Semigroup

About combination--going from two things to one thing. Note some datatypes have several semigroup instances because they can be combined in multiple ways. Int for instance. Should "5 combine 4" be 9 or 20?

Monoid

Same as semigroup only with an identity element called mempty (so for list it's [], Sum Int 0, Product Int 1, etc). Monoid requires semigroup, meaning all monoids are semigroups but not all semigroups are monoids.

Functor

Functors are structures with some data inside (hence the * -> * kindedness). The idea behind functor is to lift some function over that structure and apply it do the data inside, leaving the structure itself intact.

Applicative

Like function only instead of having a function and some structure, you have two structures. One of these has a function inside it, so the idea is to apply the function and combine the two structures.

For types like Maybe, you can think of this as extracting the function from one structure, extracting the data from another, applying one to the other, and wrapping it back in a Maybe structure. But for something like tuple, the first element in the tuple is part of the structure, so after you apply the function, you're still left with the problem of how to combine this element with its counterpart.

(<*>) is read "ap" or "apply"

Monad

The idea behind monad resembles that behind applicative. It's about applying a function to a datum inside some structure, and then possibly doing some combining (depending on the structure). The difference is that with applicative, you're given two structures up front. With monad, you're given a structure and a function that returns a structure. So you must apply the function then (potentially) combine it's result with the original structure. (Compare applicative and monad implementations of the Two--ie, tuple--datatype).

Function Algebras

General

Functions too can have a functor instance, a monad instance, etc. It may seem strange, but if you think of the function a -> b as a structure (a ->) with a type parameter b, then it becomes no different than the structure Maybe b or List b. They key to writing typeclass instances for functions is to look at the typeclass method signatures and the substitute in the function structure. For example:

fmap :: Functor f => (a -> b) -> f a -> f b

Let f be (r -> ):

fmap :: Functor f => (a -> b) -> (r -> a) -> (r -> b)

And then it's simply a matter of lining up the types.

The interesting thing about this idea is that defining monad instances for certain functions (a -> b or a -> (b, a) for example) gives us new abilities in our code.

Reader

Reader is just the function a -> b, or more conventionally r -> s. It's monad instance is useful if we have a bunch of functions that need to operate on--but not change--some global state. It's tedious to pass the global state around to all the functions so reader let's us avoid that.

State

If we need to modify state, not just read it, then the State monad is the thing. It is an instance of the funciton s -> (a, s).

Transformers

combining monadic effects with composition. State lets you modify values over time. IO lets you print. Combine them to do both. You can do this without transformers but there's a lot of tedious packaging/unpackaging values.

can only compose monads if you know one of them in advance, hence the need for transformers

building a little onion. M1 M2 means M1(M2). To evaluate you must peelM1 and THEN peelM2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.