hello = putStrLn "Hello DevFest Nantes!"
helloFred = do
putStrLn "Hello Nantes,"
putStrLn "my name is Fred!"
square x = x ^ 2
map square [1, 2, 3]
map square [1..10]
fun :: Type1 -> Type2 -> Type3 -> Type4
fun arg1 arg2 arg3 = expression
constant :: Int
constant = 2
increment :: Int -> Int
increment a = a + 1
increment a = add 1 a
simplified into
increment = add 1
Similarly
add a b = a + b
add a b = (+) a b
add = (+)
The dot operator
(.) :: (b -> c) -> (a -> b) -> a -> c
incrementTwice n = (increment . increment) n
incrementTwice = increment . increment
Functions in Haskell are like functions in maths.
Very handy for parallel computing but... how do you do anything?
map :: (a -> b) -> [a] -> [b]
map
is parametrically polymorphism: implementation doesn't depends on a
and b
.
(+) :: Num a => a -> a -> a
+
is ad-hoc polymorphism: implementation is type dependent
Num
is a type class : a trait that you can implement outside the datatype definition.
Polymorphism on return type
fromInteger :: Num a => Integer -> a
mempty :: Monoid a => a
data MyType = MyConstructor Attribute1 Attribute2
Multiple constructors possible
data Color = Red | Blue | Green
Data type can be parametric
data Vector a = Vector a
Generalize mapping over a parametric datatype
map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
fmap (+1) (Just 1)
fmap (+1) [1, 2, 3]
(*2) <$> Just 1
(*2) <$> Nothing
getLine :: IO String
getInt :: IO Int
getInt = read <$> getLine
Generalize functors to multiple arguments functions
(+) <$> Just 1 <*> Just 2
(++) <$> getLine <*> getLine
Build parser by combining other parsers, with basic parsers
char :: Char -> Parser Char
string :: String -> Parser String
space :: Parser Char
space = char ' '
oneOf :: [Char] -> Parser Char
many :: Parser a -> Parser [a]
many1 :: Parser a -> Parser [a]
parsePiece :: Parser Piece
parsePiece = decodePiece <$> oneOf "PNBRQK"
decodePiece 'P' = Pawn
decodePiece 'N' = Knight
decodePiece 'B' = Bishop
decodePiece 'R' = Rook
decodePiece 'Q' = Queen
decodePiece 'K' = King
Portable Game Notation, context of the game and notation of moves.
[Event "F/S Return Match"]
[Site "Belgrade, Serbia JUG"]
[Date "1992.11.04"]
[Round "29"]
[White "Fischer, Robert J."]
[Black "Spassky, Boris V."]
[Result "1/2-1/2"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3
O-O 9. h3 Nb8 10. d4 Nbd7 11. c4 c6 12. cxb5 axb5 13. Nc3 Bb7 14. Bg5 b4 15.
Nb1 h6 16. Bh4 c5 17. dxe5 Nxe4 18. Bxe7 Qxe7 19. exd6 Qf6 20. Nbd2 Nxd6 21.
Nc4 Nxc4 22. Bxc4 Nb6 23. Ne5 Rae8 24. Bxf7+ Rxf7 25. Nxf7 Rxe1+ 26. Qxe1 Kxf7
27. Qe3 Qg5 28. Qxg5 hxg5 29. b3 Ke6 30. a3 Kd6 31. axb4 cxb4 32. Ra5 Nd5 33.
f3 Bc8 34. Kf2 Bf5 35. Ra7 g6 36. Ra6+ Kc5 37. Ke1 Nf4 38. g3 Nxh3 39. Kd2 Kb5
40. Rd6 Kc5 41. Ra6 Nf2 42. g4 Bd3 43. Re6 1/2-1/2
PGN files can also include annotations and variations (here look at moves 19. and 22.)
[Event "Interclubs FRA"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "Calistri, Tristan"]
[Black "Bauduin, Etienne"]
[Result "1-0"]
1.e4 c5 2.Nf3 e6 3.d4 cxd4 4.Nxd4 Nc6 5.Nc3 a6 6.Be2 Qc7 7.O-O Nf6 8.Be3 Bb4
9.Na4 O-O 10.c4 Bd6 11.g3 Nxe4 12.Bf3 f5 13.Bxe4 fxe4 14.c5 Be7 {Les Noirs ont
un pion d'avance mais de gros problèmes pour mettre leur Fc8 et leur Ta8 en jeu}
15.Qg4 Ne5 16.Qxe4 d5 17.cxd6 Bxd6 18.Rac1 Qa5 19.Nb3 +/- {D} { Les blancs ont
récupéré leur pion et toutes leurs pièces sont mobilisées }
19...Qb4
(19...Qd5 20.Qxd5 exd5 21.Nb6 Bh3 22.Nxa8 Nf3+ 23.Kh1 Bxf1 24.Rxf1 Rxa8 25.Rd1±)
(19...Nf3+ 20.Kg2 Qh5)
20.Qxb4 Bxb4 21.Nb6 $18 {Les noirs n'arriveront jamais à sortir leur Fc8}
21...Rb8 22.Bc5 Bxc5
(22...Nd3 23.Bxf8 Nxc1 24.Rxc1 Bxf8 25.Rxc8 Rxc8 26.Nxc8 +/-)
23.Nxc5 Rd8 24.Rfd1 Re8 25.Ne4 Nf7 26.Rc7 Kf8 27.Rdc1 1-0
Forsyth–Edwards Notation, describes a position and let you start over from it.
rnbqkbnr/pp2pppp/2p5/3P4/3P4/8/PP2PPPP/RNBQKBNR b KQkq - 0 3
rnbqkbnr/pp2pppp/2p5/3P4/3P4/8/PP2PPPP/RNBQKBNR <-- board
b <-- player to move (w or b)
KQkq <-- available castling sides
- <-- en passant?
0 <-- half-moves since last capture
3 <-- moves
Pieces are encoded with english names
English | French | |
---|---|---|
P |
Pawn | Pion |
N |
Knight | Cavalier |
B |
Bishop | Fou |
R |
Rook | Tour |
Q |
Queen | Dame |
K |
King | Roi |
After 3. cxd5 rnbqkbnr/pp2pppp/2p5/3P4/3P4/8/PP2PPPP/RNBQKBNR b KQkq - 0 3
After 9. O-O r2qkb1r/pp3ppp/2n1pn2/3p4/3P4/2N1PB2/PP3PPP/R1BQ1RK1 b kq - 1 9
After 49. Bf5+ 8/7k/p4K2/P4B1P/1P6/8/8/8 b - - 2 49
type File = Char
type Rank = Char
type Square = (File, Rank)
data Color = White | Black
data Piece = Pawn | Knight | Bishop | Rook | Queen | King
data SquareContent = ColoredPiece Piece Color | Void
type Position = [[SquareContent]]
type EnPassant = Maybe Square
data CastlingCapacity = CanLongCastle Color | CanShortCastle Color
data Board = Board Position Color [CastlingCapacity] EnPassant Int Int
parseFile :: Parser File
parseFile = oneOf "abcdefgh"
parseRank :: Parser File
parseRank = oneOf "12345678"
parseSquare :: Parser Square
parseSquare = do
file <- parseFile
rank <- parseRank
return (file, rank)
parseSquare' :: Parser Square
parseSquare' = mkSquare <$> parseFile <*> parseRank
where mkSquare f r = (f, r)
parseSquare'' :: Parser Square
parseSquare'' = (,) <$> parseFile <*> parseRank
parseInt :: Parser Int
parseInt = read <$> many1 digit
(,,) <$> parseInt <*> space <*> parseInt
(,) <$> parseInt <* space <*> parseInt
(,) <$> parseInt <* space
<*> parseInt
instance Alternative Parser
parseColor :: Parser Color
parseColor = tries [ White <$ char 'w'
, Black <$ char 'b'
]
parseEnPassantSquare :: Parser Square
parseEnPassantSquare = (,) <$> parseFile <*> oneOf "36"
parseEnPassant :: Parser EnPassant
parseEnPassant =
tries [ Nothing <$ char '-'
, Just <$> parseEnPassantSquare
]
parseCastlingCapacity :: Parser CastlingCapacity
parseCastlingCapacity =
tries [ CanLongCastle White <$ char 'Q'
, CanShortCastle White <$ char 'K'
, CanLongCastle Black <$ char 'q'
, CanShortCastle Black <$ char 'k'
]
parseCastlingCapacities :: Parser [CastlingCapacity]
parseCastlingCapacities =
tries [ [] <$ char '-'
, many parseCastlingCapacity
]
parseRow :: Parser [SquareContent]
parseRow = assuming (ofLength 8) $ mconcat <$> many parseSquareContent
parsePosition :: Parser Position
parsePosition = assuming (ofLength 8) $ parseRow `sepBy` char '/'
boardParser :: Parser Board
boardParser = Board <$> parsePosition <* space
<*> parseColor <* space
<*> parseCastlingCapacities <* space
<*> parseEnPassant <* space
<*> parseInt <* space
<*> parseInt
colorToMove :: Board -> Color
colorToMove (Board _ color _ _ _ _) = color
canWhiteLongCastle :: Board -> Bool
canWhiteLongCastle (Board _ _ castles _ _ _) = elem whiteLongCastle castles
where whiteLongCastle = CanLongCastle White