Skip to content

Instantly share code, notes, and snippets.

@veslav3
Created November 1, 2017 19:32
Show Gist options
  • Save veslav3/16722c889b6b00a563e32549b598c8dc to your computer and use it in GitHub Desktop.
Save veslav3/16722c889b6b00a563e32549b598c8dc to your computer and use it in GitHub Desktop.

Day three the mind meld

Today I will continue with the third and last chapter of the seven languages in seven weeks book about haskell.

Classes and Types

In this section we will go over the type system in Haskell again. You can find the types like this:

Prelude> :set +t
Prelude> 'c'
'c'
it :: Char

We can also define our own types like this:

data Boolean = True | False | Cool

We can also do some more advanced stuff when creating our own types:

module Main where

main :: IO ()
main = undefined

data Suit = Spades | Hearts deriving (Show)
data Rank = Ten | Jack | Queen | King | Ace deriving (Show)
type Card = (Rank, Suit)
type Hand = [Card]

value :: Rank -> Integer
value Ten = 1
value Jack = 2
value Queen = 3
value King = 4
value Ace = 5

cardValue :: Card -> Integer
cardValue (rank, suit) = value rank

This way we can define our types to use in an application. This way you can verify the input of your function inside the programs that you write. In Java you could do something similar using enums, but I think the Haskell type functions are more advanced than the things you can do in Java.

Functions and polymorphism

If we want to use a function using generic types we can define it like this:

backwards :: [a] -> [a]
backwards [] = []
backwards (h:t) = backwards t ++ [h]

This way we can sort a list backwards using all of the different types available.

Recursive Types

For recursive types we will use a tree:

data Tree a = Children [Tree a] | Leaf a deriving (Show)

Using trees in Java as well as Haskell it is a bit hard to check the data structure you have created, but in Haskell it's even more confusing to check if you did it right, because it's harder to draw a visual representation of the tree on the screen. So far I think this is the main issue with Haskell as a language, you can easily write hard to read code and can get confused by it quite fast. Where as this isn't really the case using Java. Using the Tree defined above we can do the following:

*Main> Children[Leaf 1, Leaf 2]
Children [Leaf 1,Leaf 2]

*Main> let tree = Children[Leaf 1, Children [Leaf 2, Leaf 3]]
*Main> tree
Children [Leaf 1,Children [Leaf 2,Leaf 3]]

*Main> let (Children ch) = tree
*Main> ch
[Leaf 1,Children [Leaf 2,Leaf 3]]

*Main> let (fst: tail) = ch

*Main> fst
Leaf 1

We can see here that the first item in the tree is in fact "Leaf 1", which is correct because it has the children "Leaf 2" and "Leaf 3".

Classes

In Haskell, classes are defined as follows:

class Eq a where
  -- class body
  (==), (/=) :: a -> a -> Bool
  x /= y = not (x == y)
  x == y = not (x /= y)

A class in Haskell can be used as another way to type the functions. It defines which operations can work on which inputs. Like a protocol in Clojure. This means that they are used for a different purpose than in Java. Because there is no data involved in these classes.

Monads

data Position t = Position t deriving (Show)

stagger (Position d) = Position (d + 2)
crawl (Position d) = Position (d + 1)

rtn x = x
x >>== f = f x

treasureMap pos = pos >>==
                  stagger >>==
                  stagger >>==
                  crawl >>==
                  rtn

Day three self study

Find a few monad tutorials https://www.haskell.org/tutorial/monads.html https://wiki.haskell.org/All_About_Monads https://youtu.be/gEoruozy3mk

A list of the monads in Haskell Most common monads in Haskell:

  • Maybe
  • List
  • State
  • Reader
  • IO

Write a function that looks up a hash table value that uses the Maybe monad. Write a hash that stores other hashes, several levels deep. Use the Maybe monad to retrieve an element for a hash key several levels deep.

retrieve :: Eq a => a -> [(a, b)] -> Maybe b
retrieve _ [] = Nothing
retrieve key ((k,v):rest) =
    if key == k
       then Just v
       else retrieve key rest

testData = [ ("autos", [("Audi",[("A5","A3")]), ("BMW",[("M3","M5")]), ("Seat",[("Altea","Leon")]) ] ), ("voedsel", [("Chips",[("Paprika","Joppie")]), ("Fruit",[("Appel","Peer")]) ] ) ]

*Main> retrieve "voedsel" testData >>= retrieve "Chips" >>= retrieve "Paprika"
Just "Joppie"

*Main> retrieve "autos" testData >>= retrieve "Audi"
Just [("A5","A3")]

Respresent a maze in Haskell. You'll need a Maze type and a Node type, as well as a function to return a node given its coordinates. The node should have a list of exits to other nodes.

module Maze where
    import Data.List
    import Control.Monad

    data Node = Node { xcoord::Int,
        ycoord::Int,
        neighbours::[Node],
        is_finish::Bool,
        name::String
    } deriving (Show,Eq)

    n1 = Node{ xcoord=0, ycoord=0,
               neighbours=[n2], is_finish=False,
               name="n1" }
    n2 = Node{ xcoord=1, ycoord=0,
               neighbours=[n3], is_finish=False,
               name="n2" }
    n3 = Node{ xcoord=0, ycoord=1,
               neighbours=[n4], is_finish=False,
               name="n3" }
    n4 = Node{ xcoord=1, ycoord=1,
               neighbours=[], is_finish=True,
               name="n4" }
    n5 = Node{ xcoord=1, ycoord=2,
               neighbours=[n4,n3], is_finish=False,
               name="n5" }
    n6 = Node{ xcoord=2, ycoord=2,
               neighbours=[], is_finish=False,
               name="n6" }

Use a List monad to solve the maze.

all_exits node acc
       | neighbours node == [] = [node]
       | otherwise =
           do n <- neighbours node;
                   let { nextLot = all_exits n acc };
                       (node:nextLot)

solve start_node =
      let (pathNodes, finishNodes) = break (\ n -> is_finish n == True ) $ all_exits start_node []
      in
          if length finishNodes < 1 then
              []
          else
              pathNodes++[head finishNodes]

*Maze> map (name) $ solve n1
["n1","n2","n3","n4"]

Implement a Monad in a nonfunctional language. (See the article series on monads in Ruby)

public class Monad {
    public static Optional<Integer> optionalAdd(Optional<Integer> val1, Optional<Integer> val2) {
        return
                val1.flatMap( first ->
                        val2.flatMap( second ->
                                Optional.of(first + second)
                        ));
    }

    public static void main(String[] args) {
        System.out.println("Two integers added with an optional: " + optionalAdd(Optional.of(1), Optional.of(5)));

        System.out.println("One integer + empty value: " + optionalAdd(Optional.of(1), Optional.empty()));
    }
}
    
// result:
Two integers added with an optional: Optional[6]
One integer + empty value: Optional.empty

I made a function using the Java Optional monad. With this function you can add the optionals, but it doesn't add them when a value isn't provided. In that case it will return an empty optional.

Wrapping up

Today I learned all the basics about Haskell. I think Haskell is a very interesting language, and I want to try to make a tic tac toe challenge to test the skills that I gained so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment