Note: Every time you see a delimiter with a file name and a.lhs
extension,
You can download it.
If you save the file asfilename.lhs
, you can run it with
runhaskell filename.lhs
Some examples may not work, but most should.
Below you should see a link to the file.
ghc
: A compiler similar to gcc for C
ghci
: Haskell interactive shell (REPL)runhaskell
: Run the program without compiling it. Convenient, but very slow compared to compiled programs. main = putStrLn "Hello World!"
hello.hs
and execute:
~ runhaskell ./hello.hs Hello World!
00_hello_world.lhs
file and execute:
~ runhaskell 00_hello_world.lhs Hello World!
main = do print " ?" name <- getLine print (" " ++ name ++ "!")
# Python print " ?" name = raw_input() print " %s!" % name
# Ruby puts " ?" name = gets.chomp puts " #{name}!"
// In C #include <stdio.h> int main (int argc, char **argv) { char name[666]; // <- ! // , 665 ? printf(" ?\n"); scanf("%s", name); printf(" %s!\n", name); return 0; }
main
function is IO ()
.
main
creates side effects.
C
, C++
or Java
, the type system will help you.
Calling a function with the same parameters will always give the same result.
>>=
, <$>
, <-
or other scary characters, just ignore them and try to understand the general idea of ​​the code.
C
:
int f(int x, int y) { return x*x + y*y; }
function f(x,y) { return x*x + y*y; }
def f(x,y): return x*x + y*y
def f(x,y) x*x + y*y end
(define (fxy) (+ (* xx) (* yy)))
fxy = x*x + y*y
def
.
-- :: f :: Int -> Int -> Int fxy = x*x + y*y main = print (f 2 3)
~ runhaskell 20_very_basic.lhs 13
f :: Int -> Int -> Int fxy = x*x + y*y main = print (f 2.3 4.2)
21_very_basic.lhs:6:23: No instance for (Fractional Int) arising from the literal `4.2' Possible fix: add an instance declaration for (Fractional Int) In the second argument of `f', namely `4.2' In the first argument of `print', namely `(f 2.3 4.2)' In the expression: print (f 2.3 4.2)
4.2
is not int.
f
.
fxy = x*x + y*y main = print (f 2.3 4.2)
C
, you would need to create a function for int
, for float
, for long
, for double
, etc.
% ghci GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Loading package ffi-1.0 ... linking ... done. Prelude> let fxy = x*x + y*y Prelude> :type f f :: Num a => a -> a -> a
Num a => a -> a -> a
a -> a -> a
.
Specified type | Value |
Int | Int type |
Int -> Int | a function that takes an Int as input and returns an Int |
Float -> Int | function that takes an input Float and returns an Int |
a -> Int | the type of the function that accepts any type of input and returns an Int |
a -> a | the type of the function, which takes type a as input and returns the result of type a |
a -> a -> a | the type of the function that takes two arguments of type a as input and returns the result of type a |
a -> a -> a
, the letter a
is a type variable .
f
is a function of two arguments, and both arguments, as well as the result, have the same type.
a
can take values ​​of various types.
Int
, Integer
, Float
...
C
and separately define functions for int
, long
, float
, double
, etc. ...
a
can be of any type.
String
, Int
, more complex type, such as Trees
, type of another function, etc.
Num a =>
.
Num
is a type class .
Num
includes only types that behave like numbers.
Num
is a class containing types that implement a given set of functions, in particular (+)
and (*)
.
Num a => a -> a -> a
means:
a
be a
type belonging to the class of types Num
.
a
and returns ( a -> a
).
f 3 4
equivalent to (f 3) 4
.
f 3
is also a function:
f :: Num a :: a -> a -> a g :: Num a :: a -> a g = f 3 gy ⇔ 3*3 + y*y
g = \y -> 3*3 + y*y
\
character is used because it is similar to the λ
character, but at the same time it is an ASCII character.
f :: Num a => a -> a -> a fxy = x*x + y*y main = print (f 3 2.4)
3
can represent either a Fractional (fractional) number of type Float, or an integer of type Integer.
2.4
is of type Fractional, 3
also represented as a Fractional number.
f :: Num a => a -> a -> a fxy = x*x + y*y x :: Int x = 3 y :: Float y = 2.4 main = print (fxy) -- , x ≠y
⇔
to show the equivalence of two expressions.
⇒
symbol will be used to show the result of evaluating an expression.
3 + 2 * 6 / 3 ⇔ 3 + ((2*6)/3)
True || False ⇒ True True && False ⇒ False True == False ⇒ False True /= False ⇒ True (/=)
x^n n (Int Integer) x**y y ( Float)
Integer
not limited in size, except for the memory of the machine:
4^103 102844034832575377634685573909834406561420991602098741459288064
Data.Ratio
module:
$ ghci .... Prelude> :m Data.Ratio Data.Ratio> (11 % 15) * (5 % 3) 11 % 9
[] ⇔ [1,2,3] ⇔ ["foo","bar","baz"] ⇔ (String) 1:[2,3] ⇔ [1,2,3], (:) 1:2:[] ⇔ [1,2] [1,2] ++ [3,4] ⇔ [1,2,3,4], (++) [1,2,3] ++ ["foo"] ⇔ String ≠Integral [1..4] ⇔ [1,2,3,4] [1,3..10] ⇔ [1,3,5,7,9] [2,3,5,7,11..100] ⇔ ! ! [10,9..1] ⇔ [10,9,8,7,6,5,4,3,2,1]
Char
.
'a' :: Char "a" :: [Char] "" ⇔ [] "ab" ⇔ ['a','b'] ⇔ 'a':"b" ⇔ 'a':['b'] ⇔ 'a':'b':[] "abc" ⇔ "ab"++"c"
Note :
In real-world tasks, you will not use a list of characters for working with text.
In most cases,Data.Text
used for this.
If you need to work with a stream of ASCII characters, you should useData.ByteString
.
(a,b)
.
-- - (2,"foo") (3,'a',[2,3]) ((2,"a"),"c",3) fst (x,y) ⇒ x snd (x,y) ⇒ y fst (x,y,z) ⇒ ERROR: fst :: (a,b) -> a snd (x,y,z) ⇒ ERROR: snd :: (a,b) -> b
($)
and (.)
.
-- : fghx ⇔ (((fg) h) x) -- $ $ -- fg $ hx ⇔ fg (hx) ⇔ (fg) (hx) f $ ghx ⇔ f (ghx) ⇔ f ((gh) x) f $ g $ hx ⇔ f (g (hx)) -- (.) (f . g) x ⇔ f (gx) (f . g . h) x ⇔ f (g (hx))
x :: Int ⇔ x Int x :: a ⇔ x x :: Num a => a ⇔ x a, Num f :: a -> b ⇔ f a b f :: a -> b -> c ⇔ f , a (b→c) f :: (a -> b) -> c ⇔ f , (a→b) c
square :: Num a => a -> a square x = x^2
^
used in infix notation.
square' x = (^) x 2 square'' x = (^2) x
x
from the left and right side of the expression!
square''' = (^2)
'
in the function name.
square
⇔square'
⇔square''
⇔square '''
absolute :: (Ord a, Num a) => a -> a absolute x = if x >= 0 then x else -x
if .. then .. else
in Haskell is more like an operator
¤?¤:¤
in C. You cannot omit else
.
absolute' x | x >= 0 = x | otherwise = -x
Warning: alignment is important in Haskell programs.
As in Python, incorrect alignment can break the code!
Having a list of integers, you must calculate the sum of even numbers in the list.
example:
[1,2,3,4,5] ⇒ 2 + 4 ⇒ 6
function evenSum(list) { var result = 0; for (var i=0; i< list.length ; i++) { if (list[i] % 2 ==0) { result += list[i]; } } return result; }
Note :
Recursion in imperative languages ​​has a reputation as a slow tool. But for most functional languages ​​this is not the case. In most cases, Haskell optimizes work with recursive functions in a very high quality.
C
For simple, I assume that the list of numbers ends with a null value.
int evenSum(int *list) { return accumSum(0,list); } int accumSum(int n, int *list) { int x; int *xs; if (*list == 0) { // if the list is empty return n; } else { x = list[0]; // let x be the first element of the list xs = list+1; // let xs be the list without x if ( 0 == (x%2) ) { // if x is even return accumSum(n+x, xs); } else { return accumSum(n, xs); } } }
even :: Integral a => a -> Bool head :: [a] -> a tail :: [a] -> [a]
even
parity check.
even :: Integral a => a -> Bool even 3 ⇒ False even 2 ⇒ True
head
returns the first item in the list:
head :: [a] -> a head [1,2,3] ⇒ 1 head [] ⇒ ERROR
tail
returns all list items, except for the first:
tail :: [a] -> [a] tail [1,2,3] ⇒ [2,3] tail [3] ⇒ [] tail [] ⇒ ERROR
l
,
l ⇔ (head l):(tail l)
evenSum
function returns the sum of all even numbers in the list:
-- 1 evenSum :: [Integer] -> Integer evenSum l = accumSum 0 l accumSum nl = if l == [] then n else let x = head l xs = tail l in if even x then accumSum (n+x) xs else accumSum n xs
ghci
:
% ghci GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :load 11_Functions.lhs [1 of 1] Compiling Main ( 11_Functions.lhs, interpreted ) Ok, modules loaded: Main. *Main> evenSum [1..5] 6
*Main> evenSum [1..5] accumSum 0 [1,2,3,4,5] 1 is odd accumSum 0 [2,3,4,5] 2 is even accumSum (0+2) [3,4,5] 3 is odd accumSum (0+2) [4,5] 4 is even accumSum (0+2+4) [5] 5 is odd accumSum (0+2+4) [] l == [] 0+2+4 0+6 6
evenSum :: Integral a => [a] -> a
where
or let
.
accumSum
function accumSum
not pollute the global namespace.
-- 2 evenSum :: Integral a => [a] -> a evenSum l = accumSum 0 l where accumSum nl = if l == [] then n else let x = head l xs = tail l in if even x then accumSum (n+x) xs else accumSum n xs
-- 3 evenSum l = accumSum 0 l where accumSum n [] = n accumSum n (x:xs) = if even x then accumSum (n+x) xs else accumSum n xs
foo l = if l == [] then <x> else <y>
foo [] = <x> foo l = <y>
foo l = let x = head l xs = tail l in if even x then foo (n+x) xs else foo n xs
foo (x:xs) = if even x then foo (n+x) xs else foo n xs
fx = (- ) x
f = -
l
:
-- 4 evenSum :: Integral a => [a] -> a evenSum = accumSum 0 where accumSum n [] = n accumSum n (x:xs) = if even x then accumSum (n+x) xs else accumSum n xs
filter :: (a -> Bool) -> [a] -> [a] map :: (a -> b) -> [a] -> [b] foldl :: (a -> b -> a) -> a -> [b] -> a
-- 5 evenSum l = mysum 0 (filter even l) where mysum n [] = n mysum n (x:xs) = mysum (n+x) xs
filter even [1..10] ⇔ [2,4,6,8,10]
filter
function accepts a function of type ( a -> Bool
) and a list of type [a]
as arguments. It returns a list containing only those elements for which the function returned true
.
foldl
function, which allows you to accumulate a value. The foldl
function implements a popular programming technique:
myfunc list = foo initialValue list foo accumulated [] = accumulated foo tmpValue (x:xs) = foo (bar tmpValue x) xs
myfunc list = foldl bar initialValue list
foldl
shown below.
foldl fz [] = z foldl fz (x:xs) = foldl f (fzx) xs
foldl fz [x1,...xn] ⇔ f (... (f (fz x1) x2) ...) xn
(fzx)
, but pushes it (fzx)
stack.
foldl'
instead of foldl
;
foldl'
is a strict (or energetic) implementation of foldl
.
evenSum
looks like this:
-- 6 -- foldl' -- Data.List import Data.List evenSum l = foldl' mysum 0 (filter even l) where mysum acc value = acc + value
mysum
.
-- 7 -- -- import Data.List (foldl') evenSum l = foldl' (\xy -> x+y) 0 (filter even l)
(\xy -> x+y) ⇔ (+)
-- 8 import Data.List (foldl') evenSum :: Integral a => [a] -> a evenSum l = foldl' (+) 0 (filter even l)
foldl'
not the most intuitive feature. But with her, you should definitely figure it out.
evenSum [1,2,3,4] ⇒ foldl' (+) 0 (filter even [1,2,3,4]) ⇒ foldl' (+) 0 [2,4] ⇒ foldl' (+) (0+2) [4] ⇒ foldl' (+) 2 [4] ⇒ foldl' (+) (2+4) [] ⇒ foldl' (+) 6 [] ⇒ 6
(.)
.
(.)
.
(f . g . h) x ⇔ f ( g (hx))
-- 9 import Data.List (foldl') evenSum :: Integral a => [a] -> a evenSum = (foldl' (+) 0) . (filter even)
-- 10 import Data.List (foldl') sum' :: (Num a) => [a] -> a sum' = foldl' (+) 0 evenSum :: Integral a => [a] -> a evenSum = sum' . (filter even)
[1,2,3,4] â–· [1,4,9,16] â–· [4,16] â–· 20
squareEvenSum = sum' . (filter even) . (map (^2)) squareEvenSum' = evenSum . (map (^2)) squareEvenSum'' = sum' . (map (^2)) . (filter even)
squareEvenSum''
. (.)
.).
map (^2) [1,2,3,4] ⇔ [1,4,9,16]
map
- .
tl;dr :
type Name = AnotherType
,Name
AnotherType
.data Name = NameConstructor AnotherType
.data
.deriving
.
square
Haskell:
square x = x * x
square
( ) Numeral.
Int
, Integer
, Float
, Fractional
Complex
. For example:
% ghci GHCi, version 7.0.4: ... Prelude> let square x = x*x Prelude> square 2 4 Prelude> square 2.1 4.41 Prelude> -- Data.Complex Prelude> :m Data.Complex Prelude Data.Complex> square (2 :+ 1) 3.0 :+ 4.0
x :+ y
( x + iy ).
int int_square(int x) { return x*x; } float float_square(float x) {return x*x; } complex complex_square (complex z) { complex tmp; tmp.real = z.real * z.real - z.img * z.img; tmp.img = 2 * z.img * z.real; } complex x,y; y = complex_square(x);
#include <iostream> #include <complex> using namespace std; template<typename T> T square(T x) { return x*x; } int main() { // int int sqr_of_five = square(5); cout << sqr_of_five << endl; // double cout << (double)square(5.3) << endl; // complex cout << square( complex<double>(5,3) ) << endl; return 0; }
“ , ”
type Name = String type Color = String showInfos :: Name -> Color -> String showInfos name color = "Name: " ++ name ++ ", Color: " ++ color name :: Name name = "Robin" color :: Color color = "Blue" main = putStrLn $ showInfos name color
showInfos
:
putStrLn $ showInfos color name
data
.
data Name = NameConstr String data Color = ColorConstr String showInfos :: Name -> Color -> String showInfos (NameConstr name) (ColorConstr color) = "Name: " ++ name ++ ", Color: " ++ color name = NameConstr "Robin" color = ColorConstr "Blue" main = putStrLn $ showInfos name color
showInfos
, . . .
NameConstr :: String -> Name ColorConstr :: String -> Color
data
:
data TypeName = ConstructorName [types] | ConstructorName2 [types] | ...
data Complex = Num a => Complex aa
data DataTypeName = DataConstructor { field1 :: [type of field1] , field2 :: [type of field2] ... , fieldn :: [type of fieldn] }
data Complex = Num a => Complex { real :: a, img :: a} c = Complex 1.0 2.0 z = Complex { real = 3, img = 4 } real c ⇒ 1.0 img z ⇒ 4
data List a = Empty | Cons a (List a)
infixr 5 ::: data List a = Nil | a ::: (List a)
infixr
— .
Show
), ( Read
), ( Eq
) ( Ord
) , Haskell-, .
infixr 5 ::: data List a = Nil | a ::: (List a) deriving (Show,Read,Eq,Ord)
deriving (Show)
, Haskell show
. , show
.
convertList [] = Nil convertList (x:xs) = x ::: convertList xs
main = do print (0 ::: 1 ::: Nil) print (convertList [0,1])
0 ::: (1 ::: Nil) 0 ::: (1 ::: Nil)
import Data.List data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Show)
treeFromList :: (Ord a) => [a] -> BinTree a treeFromList [] = Empty treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs)) (treeFromList (filter (>x) xs))
(x:xs)
, :
x
xs
x
xs
x
. main = print $ treeFromList [7,2,4,8]
Node 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)
deriving (Show)
BinTree
. BinTree ( Eq
Ord
). .
data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Eq,Ord)
deriving (Show)
, Haskell show
.
show
. , , BinTree a
Show
.
instance Show (BinTree a) where show t = ... --
-- BinTree Show instance (Show a) => Show (BinTree a) where -- '<' -- : show t = "< " ++ replace '\n' "\n: " (treeshow "" t) where -- treeshow pref Tree -- pref -- treeshow pref Empty = "" -- Leaf treeshow pref (Node x Empty Empty) = (pshow pref x) -- treeshow pref (Node x left Empty) = (pshow pref x) ++ "\n" ++ (showSon pref "`--" " " left) -- treeshow pref (Node x Empty right) = (pshow pref x) ++ "\n" ++ (showSon pref "`--" " " right) -- treeshow pref (Node x left right) = (pshow pref x) ++ "\n" ++ (showSon pref "|--" "| " left) ++ "\n" ++ (showSon pref "`--" " " right) -- showSon pref before next t = pref ++ before ++ treeshow (pref ++ next) t -- pshow "\n" "\n"++pref pshow pref x = replace '\n' ("\n"++pref) (show x) -- replace c new string = concatMap (change c new) string where change c new x | x == c = new | otherwise = x:[] -- "x"
treeFromList
.
treeFromList :: (Ord a) => [a] -> BinTree a treeFromList [] = Empty treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs)) (treeFromList (filter (>x) xs))
main = do putStrLn "Int binary tree:" print $ treeFromList [7,2,4,8,1,3,6,21,12,23]
print $ treeFromList [7,2,4,8,1,3,6,21,12,23] Int binary tree: < 7 : |--2 : | |--1 : | `--4 : | |--3 : | `--6 : `--8 : `--21 : |--12 : `--23
<
. :
.
putStrLn "\nString binary tree:" print $ treeFromList ["foo","bar","baz","gor","yog"]
String binary tree: < "foo" : |--"bar" : | `--"baz" : `--"gor" : `--"yog"
putStrLn "\n :" print ( treeFromList (map treeFromList ["baz","zara","bar"]))
: < < 'b' : : |--'a' : : `--'z' : |--< 'b' : | : |--'a' : | : `--'r' : `--< 'z' : : `--'a' : : `--'r'
:
.
putStrLn "\nTree of Binary trees of Char binary trees:" print $ (treeFromList . map (treeFromList . map treeFromList)) [ ["YO","DAWG"] , ["I","HEARD"] , ["I","HEARD"] , ["YOU","LIKE","TREES"] ]
print ( treeFromList ( map treeFromList [ map treeFromList ["YO","DAWG"] , map treeFromList ["I","HEARD"] , map treeFromList ["I","HEARD"] , map treeFromList ["YOU","LIKE","TREES"] ]))
Binary tree of Binary trees of Char binary trees: < < < 'Y' : : : `--'O' : : `--< 'D' : : : |--'A' : : : `--'W' : : : `--'G' : |--< < 'I' : | : `--< 'H' : | : : |--'E' : | : : | `--'A' : | : : | `--'D' : | : : `--'R' : `--< < 'Y' : : : `--'O' : : : `--'U' : : `--< 'L' : : : `--'I' : : : |--'E' : : : `--'K' : : `--< 'T' : : : `--'R' : : : |--'E' : : : `--'S'
"I","HEARD"
. () , Tree Eq
.
( ) .
(a+(b*c))
,+
,(b*c)
-- numbers = [1,2,..] numbers :: [Integer] numbers = 0:map (1+) numbers take' n [] = [] take' 0 l = [] take' n (x:xs) = x:take' (n-1) xs main = print $ take' 10 numbers
, .
[1..] ⇔ [1,2,3,4...] [1,3..] ⇔ [1,3,5,7,9,11...]
take
take'
.
nullTree = Node 0 nullTree nullTree
-- BinTree -- treeTakeDepth _ Empty = Empty treeTakeDepth 0 _ = Empty treeTakeDepth n (Node x left right) = let nl = treeTakeDepth (n-1) left nr = treeTakeDepth (n-1) right in Node x nl nr
main = print $ treeTakeDepth 4 nullTree
< 0 : |-- 0 : | |-- 0 : | | |-- 0 : | | `-- 0 : | `-- 0 : | |-- 0 : | `-- 0 : `-- 0 : |-- 0 : | |-- 0 : | `-- 0 : `-- 0 : |-- 0 : `-- 0
iTree = Node 0 (dec iTree) (inc iTree) where dec (Node xlr) = Node (x-1) (dec l) (dec r) inc (Node xlr) = Node (x+1) (inc l) (inc r)
map
, BinTree
.
-- Tree treeMap :: (a -> b) -> BinTree a -> BinTree b treeMap f Empty = Empty treeMap f (Node x left right) = Node (fx) (treeMap f left) (treeMap f right)
map
, functor() fmap
.
infTreeTwo :: BinTree Int infTreeTwo = Node 0 (treeMap (\x -> x-1) infTreeTwo) (treeMap (\x -> x+1) infTreeTwo)
main = print $ treeTakeDepth 4 infTreeTwo
< 0 : |-- -1 : | |-- -2 : | | |-- -3 : | | `-- -1 : | `-- 0 : | |-- -1 : | `-- 1 : `-- 1 : |-- 0 : | |-- -1 : | `-- 1 : `-- 2 : |-- 1 : `-- 3
Source: https://habr.com/ru/post/152889/