Archive for category Haskell
Meeting 12 – Project Discussion
Posted by Paulo Matos in Haskell on March 4, 2008
This meeting was yet again a discussion about our project: A Chess Engine.
We started out by reviewing the basics of Chess:
- Board
- Pieces
- Piece Movement
We then discussed four important exceptions in piece movement:
And we still discussed two major strategies to reduce the search space in Chess:
So that we can starting developing some code, we paired up to do (for this first week) the same code functionality:
- Board, Piece, and Position Datatypes;
- Piece Movement Function;
In order to be able to develop a driver to test the written code I assume everyone will implement datatypes:
- Board : With board information;
- Position : A position in the board;
- Piece : Piece describes a piece type with a specific color;
- PieceType : A type of piece like Rook, King, etc..;
- PieceColour : Either Black or White;
and the following functions:
-- Initialises a board to the initial chess position
initBoard :: Board
-- Moves a piece on the board from the first position to a second position
-- Returns a board with a final state or nothing is move is invalid
movePiece :: Board -> Position -> Position -> Maybe Board
-- Board selector
getPiece :: Board -> Position -> Maybe Piece
-- Piece selectors
pieceColor :: Piece -> PieceColor
pieceType :: Piece -> PieceType
-- Piece predicates
blackColor :: PieceColor -> Bool
whiteColor :: PieceColor -> Bool
rookPieceType :: PieceType -> Bool
knightPieceType :: PieceType -> Bool
bishopPieceType :: PieceType -> Bool
kingPieceType :: PieceType -> Bool
queenPieceType :: PieceType -> Bool
pawnPieceType :: PieceType -> Bool
-- Position selectors
positionRow :: Position -> Int
positionCol :: Position -> Int
-- Position constructor Assume numbers are given in order row,column and they are always from [1 .. 8].
makePosition :: Int -> Int -> Position
We’re all eager to see the developed code…
I hope you are too…
Meeting 11 – Project Presentation
Posted by Paulo Matos in Haskell on February 1, 2008
As tiped out before, there was already an idea to develop an application in Haskell to make use of what we have learned during the first term and to develop this knowledge.
Given that reading papers showed off to be a bad move in the group because most of the members would end up not reading them, we will just move to the development of the application and read any papers that might be needed during the development phase. This hopefully, might turn up to me more motivational.
The idea is to develop a game, more specifically a chess engine. There are several reasons for this decision. From this meeting a report was produced, which you can find here (as well as in our svn repository).
[Sorry for the lack of content in these posts but rest assured soon enough you'll have enough code to play with!]
Meeting 10 – Ropes and Zippers
Posted by Paulo Matos in Haskell on January 15, 2008
The FPSIG is back in action for 2008. As discussed previously we would start by looking at four papers about data structures.
Today was the time for Ropes and Zippers:
We read the papers and tried to understand the data structures. It was commonly agreed that we should take another meeting to understand these better, so that would the plan for next week.
However, people around here tend to have to read papers for either their PhD or PostDoc works which means, they are already quite bored with it and putting them in a group where they have to read papers is detrimental to the groups motivation as I could observe during todays meeting. So, during next meeting there will be a shift in the groups direction.
Meeting 9 – Monads, the end of the beginning…
Posted by Paulo Matos in Haskell on December 11, 2007
Toto, I’ve got a feeling we’re not in Kansas anymore.
— Dorothy (Wizard of Oz, 1939)
And indeed, we’re not! In this meeting we finished our study of Monads (but we have no illusions, we do know this is just the beginning). I have proposed an exercise and asked Antonio to present us his solution and so he did. The exercise proposal was something like:
- Define an ADT (Tree a) which represents a binary tree with values of type a at the nodes and empty leafs.
- Define the function:
countSumT :: Tree Int -> M (Int, Int)This function receives a tree of Integers and:
- returns a monad with the values of the sum of all nodes and the total number of nodes in the tree;
- prints to the screen the values of all nodes as they are searched.
The presented solution was (modulo variable renaming):
module Tree
where
data Tree a = Leaf
| Branch (Tree a) a (Tree a)
countSumT :: Tree Int -> IO (Int, Int)
countSumT Leaf = return (0, 0)
countSumT (Branch lTree val rTree) =
do
putStr "Searching Node "
putStrLn $ show val
(sumNodesLeft, countNodesLeft) <- countSumT lTree
(sumNodesRight, countNodesRight) <- countSumT rTree
return (sumNodesLeft + sumNodesRight + val, countNodesLeft + countNodesRight + 1)
In fact, when I thought about the exercise proposal my intention was to use the State monad, however, I forgot that you really don't need to use the state monad since the computation of the pair (Int, Int) is purely functional so the exercise was a bit easier then expected. Afterwards we moved on to solve the first 2 exercised in Exercises for Monads (by Simon Thompson).
Our solution for exercise 1 is as follows:
-
comp f g = (\a -> (f a) >>= g)
-
join m = m >>= id
-
liftM f = (\ma -> ma >>= (\x -> return (f x)))
Exercise 2 solution is:
ma >>= f = comp id f ma
And that's is it. This is the end of 2007 meetings. We'll restart on January 8th, 2008, same time, same place.
However, you can't go for Christmas vacations without the warmth of a goo'old functional programming paper, so I suggested the reading of the following papers:
- The Zipper
- Ropes: An alternative to Strings
- Finger Trees: A Simple General-purpose Data Structure
- Dynamic Ordered Sets with Exponential Search Trees
In the first two meetings of 2008, we'll have the readers of the papers (I'm expecting people to volunteer for this) presenting the paper for 30 mins each, so we have 2 sessions for 4 papers.
After that, we'll start developing an application in Haskell. Members already know what it is... For you, dear reader... it'll be a surprise! Stay tuned!
Meeting 8 – Ahhh, Monads…
Posted by Paulo Matos in Haskell on December 4, 2007
This meeting kept up with the subject of monads. It was out intention to understand really what are monads, what’s their interest, their place in Haskell and to try out some code with them.
Since not all members had joined us in the last session we did some brief review of what last session was all about and I proceeded to explain the enlightenment I had during this week. The tutorial which seemed to finally enlighten me was: All About Monads.
Throughout the meeting I explained with my own words what I caught up from the three parts of the tutorial I had assimilated:
Nothing new was shown this week. By reading the parts I linked to you should keep up to what we learned.
Next week we will hopefully solve an exercise involving monads (ah, some monads code) and finish this tutorial.
Moreover, since it is our last meeting until Christmas we shall also discuss what’ll happen in 2008. Stay tuned…
Meeting 7 – Monads
Posted by Paulo Matos in Haskell on November 27, 2007
Monads: Are they wierd or just different? opened up todays discussion and introduction of monads which was lead by John Colley.
Although this was mainly about Monads, it was also presented the exercise which was missing from last week:
module BinaryTree
where
import Data.Maybe
data BTree a = Leaf a
| Branch (BTree a) a (BTree a)
findAllPath :: (a -> Bool) -> (BTree a) -> [[a]]
findAllPath pred = g where
g (Leaf l) | pred l = [[l]]
g (Branch lf r rt) | pred r = map (r:) $ (findAllPath pred lf) ++ (findAllPath pred rt)
g _ = []
Needless to say that the last meeting find(All)Path resembled nothing like good Haskell code. I think this one is nearer the goal. And this one, definitely seems to do it truly lazily, i.e., if you just ask for the head of the resulting list, nothing else should be computed. Now, why the other is different, I don’t know.
To do this experimentation, I tried to define:
genTree1 :: Int -> (BTree Int)
genTree1 0 = Leaf 1
genTree1 n = Branch (genTree1 (n-1)) 1 (genTree1 (n-1))
Needless to say, this will generate a tree with 1’s at the nodes and leafs with n levels.
You try (GHCi 6.6.1):
*BinaryTree> :set +s
*BinaryTree> head $ findAllPath (\x -> True) (genTree1 100000)
[1,1,1,1,1...]
(1.56 secs, 210968808 bytes)
Now, with the version from meeting 6:
*BinaryTree> :set +s
*BinaryTree> head $ fromJust $ findAllPath (\x -> True) (genTree1 100000)
*** Exception: stack overflow
Other values, like 10000, 100 or even 50 take a huge amount of time. Why?
The next part of the session (most of it) dealt with understanding monads. John Colley prepared some code for us to study and discuss. Here it is:
-- Variations on an Evaluator
--
-- Derived from
-- [1] Bird R., Introduction to Functional Programming using
-- Haskell, 2nd Ed 1988
-- [2] Wadler P., Monads for Functional Programming, Lecture
-- Notes In Computer Science; Vol. 925, 1995
-- [3] Hudak P., Peterson J., A Gentle Introduction to
-- Haskell 98, 1999
module Eval where
-- An evaluator that acts on simple terms
-- Either a term is a constant integer or a quotient "Div t u"
-- where t and u are terms
data Term = Con Int | Div Term Term
eval :: Term -> Int
eval (Con a) = a
eval (Div t u) = eval t `div` eval u
-- Some data
answer,evalerror :: Term
answer = (Div (Div (Con 1972) (Con 2)) (Con 23))
evalerror = (Div (Con 1) (Con 0))
-- *Eval> eval answer
-- 42
-- *Eval> eval evalerror
-- *** Exception: divide by zero
-- Note that GHC raises an exception - in the above references
-- this must be done by the programmer
-- Now we want to count the number of evaluations of `div`
-- but we can't just have a global variable as in other
-- programmming languages,
-- so introduce a type to represent computations that act
-- on state: a "state transformer"
newtype St a = MkSt (State -> (a, State ))
type State = Int
-- Introduce an auxiliary function "apply" that applies a
-- state transformer to a state, giving a value/state pair
apply :: St a -> State -> (a,State)
apply (MkSt f) s = f s
-- Now eval must (tediously) be re-written
seval :: Term -> St Int
seval (Con x) = MkSt f
where f s = (x, s)
seval (Div t u) = MkSt f
where
f s = (x `div` y, s'' + 1)
where
(x,s') = apply (seval t) s
(y,s'') = apply (seval u) s'
-- (Note Bird's use of s' and s'' to represent the state values)
-- and we also need to specify how the state transformer is
-- to be displayed
instance Show a => Show (St a) where
show f = "value: " ++ show x ++ ", count: " ++ show s
where (x,s) = apply f 0
-- *Eval> seval answer
-- value: 42, count: 2
-- *Eval> seval evalerror
-- value: *** Exception: divide by zero
-- Now rewrite the the original evaluator to use a monad
meval :: Monad m => Term -> m Int
meval (Con x) = return x
meval (Div t u) = do x <- meval t
y <- meval u
return (x `div` y)
-- "meval" takes a term and performs a 'computation' m,
-- yielding an integer
-- In the state monad, a computation accepts an initial state and
-- returns a value paired with the final state
instance Monad St where
return x = MkSt f
where f s = (x,s)
p >>= q = MkSt f
where
f s = apply (q x) s'
where (x, s') = apply p s
-- define an operation to increment the state
tick :: St ()
tick = MkSt f
where f s = ((),s + 1)
-- and now it is only necessary to make a small local change
-- to meval to add a call to "tick"
mevalSt :: Term -> St Int
mevalSt (Con x) = return x
mevalSt (Div t u) = do x <- mevalSt t
y <- mevalSt u
tick
return (x `div` y)
-- *Eval> mevalSt answer
-- value: 42, count: 2
-- *Eval> mevalSt evalerror
-- value: *** Exception: divide by zero
Most of the discussion went through by looking at the code and Haskell 98 tutorial ([3] of the code above).
We have also managed to convert mevalSt main body to its monad look:
(mevalSt t) >>= (\x ->
((mevalSt u) >>= (\y ->
(tick >>= (\_ ->
return (x `div` y))))))
And so it ended this meeting. Next meeting we keep on with monads.
However, to end I asked the participants a quick quote about monads. Here’s what I got:
“Where do you find the monad in the Monad?”
— Ross Horne
“Writing Haskell in the monadic style promises better extensibility, but using the monadic meta-language takes you back into the old world of sequential programming – there must be more to this than meets the eye…”
— John Colley
“Monads seems one of those concepts which you have to mess with long enough (without panicking) until you internalise what they really do and mean.”
— Paulo Matos
Meeting 6 – The Fold and Binary Tree Amusements
Posted by Paulo Matos in Haskell on November 20, 2007
For this meeting I had proposed an exercise based on the data structure of Meeting 5:
Implement a function with type:
findPath :: (a -> Bool) -> BTree a -> Just [a]which given a function from a’s to Bool and a tree returns a path on the tree (a list of a’s representing any path) where all a’s satisfy the function passed in as first argument. Is no path exists, it should return Nothing.
For this exercise I received several solutions. Most would resemble something like:
module BinaryTree
where
import Data.Maybe
data BTree a = Leaf a
| Branch (BTree a) a (BTree a)
findPath :: (a -> Bool) -> (BTree a) -> Maybe [a]
findPath pred (Leaf l) | pred l = Just [l]
| otherwise = Nothing
findPath pred (Branch lf r rt) | pred r = let slf = findPath pred lf
in
if (isNothing slf)
then let srt = findPath pred rt
in
if (isNothing srt)
then Nothing
else Just (r : (fromJust srt))
else Just (r : (fromJust slf))
| otherwise = Nothing
The suggestion to the code was: “Hey, we’re programming in a lazy programming language. Let’s just compute all of the Paths that meet the requirement of the predicate and ask just for the first.
And so we did extrapolating from the previous function:
findAllPath :: (a -> Bool) -> (BTree a) -> Maybe [[a]]
findAllPath pred (Leaf l) | pred l = Just [[l]]
| otherwise = Nothing
findAllPath pred (Branch lf r rt) | pred r = let lfpaths = findAllPath pred lf
rtpaths = findAllPath pred rt
in
if isNothing lfpaths && isNothing rtpaths
then Nothing
else
if isNothing lfpaths
then Just (map (r:) $ fromJust rtpaths)
else
if isNothing rtpaths
then Just (map (r:) $ fromJust lfpaths)
else Just (map (r:) $ fromJust rtpaths ++ fromJust lfpaths)
| otherwise = Nothing
Lots of comments were made regarding this function, the important one however is that this doesn’t seem to computing the solution lazily. By this I mean that if I just want the first solution I can do:
head $ fromJust $ findAllPath (...)
this seems, in this particular case, to compute more than just the head.
Two questions arise:
- Is it? (computing more that what it is needed)
- If yes, why? (and devise a better procedure such that you can define findPath using findAllPath without a slow-down)
The better procedure is the suggested exercise for next week.
In this meeting we also looked at what folds really are. We learned that it is a Catamorphism and that in general a fold can be implemented for any function (I wish we had the time to gather around and write yet another fold tutorial).
We implemented, however, a fold for our tree:
foldTree :: (b -> a -> b -> b) -> (a -> b) -> (BTree a) -> b
foldTree fbranch fleaf = g where
g (Leaf x) = fleaf x
g (Branch lf r rt) = fbranch (g lf) r (g rt)
Meeting 5 – Data Types
Posted by Paulo Matos in Haskell on November 15, 2007
This meeting was the meeting we started to look at the definition of ADTs. We read the chapter 4.5 and we did a few exercises dealing with the definition of new datatypes.
Moreover, we looked at the Haskell datatypes:
- Maybe
- Either
We also defined some datatypes, one of them being the binary tree:
data BTree a = Leaf a
| Branch (BTree a) a (BTree a)
Meeting 4 – Notes on Performance
Posted by Paulo Matos in Haskell on November 8, 2007
This meeting was lead by Jordi Planes and performance issues with map and fold were discussed.
Exercises 3.4 and 3.5 or YAHT were solved.
Meeting 3 – Types
Posted by Paulo Matos in Haskell on November 1, 2007
On this meeting we decided we needed to look into types. Types were somewhat already showing up in previous meetings (well, basically you can’t have Haskell without hearing a little bit about types).
This was basically chapter 4.1-4.4, and as an exercise we tried to figure out the types of the functions of the previous meeting without looking at the :t haskell output.
Definitely, a very interesting meeting, mainly because we start know to understand how important are types in Haskell… We’re sure this is just the top of the iceberg!