
Замечание: Каждый раз, когда вы увидите разделитель с именем файла и расширением.lhs,
вы можете его скачать.
Если вы сохраните файл какfilename.lhs, вы можете запустить его при помощи
runhaskell filename.lhs
Какие-то примеры могут не работать, но большинство должно.
Чуть ниже вы должны увидеть ссылку на файл

ghc: Компилятор, похожий на gcc для C.ghci: интерактивная оболочка Haskell (REPL)runhaskell: Запуск программы без ее компиляции. Удобно, но очень медленно по сравнению со скомпилированными программами.
main = putStrLn "Hello World!"hello.hs и выполните: ~ runhaskell ./hello.hs
Hello World!00_hello_world.lhs и выполняем: ~ 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 — IO ().main создает побочные эффекты.
C, C++ или Java, система типов будет помогать вам.Вызов функции с одними и теми же параметрами всегда даст один и тот же результат.
>>=, <$>, <- или другие страшные символы, просто игнорируйте их и постарайтесь понять общую идею кода.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 (f x y)
(+ (* x x) (* y y)))
f x y = x*x + y*y
def-ов.
-- Мы определям тип используя ::
f :: Int -> Int -> Int
f x y = x*x + y*y
main = print (f 2 3)
~ runhaskell 20_very_basic.lhs
13
f :: Int -> Int -> Int
f x y = 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 это не Int.f.
f x y = x*x + y*y
main = print (f 2.3 4.2)
C, вам бы понадобилось создать функцию для int, для float, для long, для double, и т.д.
% 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 f x y = x*x + y*y
Prelude> :type f
f :: Num a => a -> a -> a
Num a => a -> a -> a
a -> a -> a.| Указанный тип | Значение |
Int |
тип Int |
Int -> Int |
функция, принимающая на вход Int и возвращающая Int |
Float -> Int |
функция, принимающая на вход Float и возвращающая Int |
a -> Int |
тип функции, принимающей на вход любой тип и возвращающая Int |
a -> a |
тип функции, принимающей на вход тип a и возвращающая результат типа a |
a -> a -> a |
тип функции, принимающей на вход два аргумента типа a и возвращающая результат типа a |
a -> a -> a, буква a это переменная типа. f — функция от двух аргументов, и оба аргумента, а также результат имеют одинаковый тип.a может принимать значения различных типов.Int, Integer, Float…C и отдельно определять функции для int, long, float, double, и т.п.… a может быть любого типа. String, Int, более сложным типом, например Trees, типом другой функции, и т.д.Num a => . Num это класс типа.Num входят только те типы, которые ведут себя как числа.Num это класс, содержащий типы, реализующие заданный набор функций, в частности (+) и (*).Num a => a -> a -> a означает:a это тип, принадлежащий к классу типов Num.a и возвращающая (a -> a).f 3 4 эквивалентно (f 3) 4. f 3 это тоже функция:
f :: Num a :: a -> a -> a
g :: Num a :: a -> a
g = f 3
g y ⇔ 3*3 + y*y
g = \y -> 3*3 + y*y
\ используется потому, что он похож на символ λ, но в то же время он ASCII символ.
f :: Num a => a -> a -> a
f x y = x*x + y*y
main = print (f 3 2.4)
3 может представлять как Fractional (дробное) число типа Float, так и целое типа Integer.2.4 имеет тип Fractional, 3 тоже представляется в виде Fractional числа.
f :: Num a => a -> a -> a
f x y = x*x + y*y
x :: Int
x = 3
y :: Float
y = 2.4
main = print (f x y) -- не будет работать, поскольку тип x ≠ типу y

⇔, чтобы показать эквивалентность двух выражений.⇔.⇒ будет использоваться для того, чтобы показать результат вычисления выражения.
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 не имеет ограничений по величине, за исключением оперативной памяти машины:
4^103
102844034832575377634685573909834406561420991602098741459288064
Data.Ratio:
$ 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"
Замечание:
В реальных задачах вы не будете использовать список символов для работы с текстом.
В большинстве случаев для этого используетсяData.Text.
Если вам небходимо работать с потоком ASCII-символов, стоит использоватьData.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
($) и (.).
-- По умолчанию:
f g h x ⇔ (((f g) h) x)
-- $ заменяет скобки от $
-- до конца выражения
f g $ h x ⇔ f g (h x) ⇔ (f g) (h x)
f $ g h x ⇔ f (g h x) ⇔ f ((g h) x)
f $ g $ h x ⇔ f (g (h x))
-- (.) композиция функций
(f . g) x ⇔ f (g x)
(f . g . h) x ⇔ f (g (h x))
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
^ используется в инфиксной нотации.
square' x = (^) x 2
square'' x = (^2) x
x из левой и правой части выражения!
square''' = (^2)
' в имени функции.square⇔square'⇔square''⇔square '''
absolute :: (Ord a, Num a) => a -> a
absolute x = if x >= 0 then x else -x
if .. then .. else в Haskell-е больше похожа на оператор¤?¤:¤ в C. Вы не можете опустить else.
absolute' x
| x >= 0 = x
| otherwise = -x
Внимание: выравнивание важно в программах на Haskell-е.
Как и в Python-е, неправильное выравнивание может сломать код!

Имея список целых чисел, необходимо посчитать сумму четных чисел в списке.
пример:
[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;
}
Замечание:
Рекурсию в императивных языках имеет репутацию медленного инструмента. Но для большинства функциональных языков это не так. В большинстве случаев, Haskell очень качественно оптимизирует работу с рекурсивными функциями.
C. Для просты, я предполагалю, что список чисел заканчивается нулевым значением.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 проверка на четность.
even :: Integral a => a -> Bool
even 3 ⇒ False
even 2 ⇒ True
head возвращает первый элемент списка:
head :: [a] -> a
head [1,2,3] ⇒ 1
head [] ⇒ ERROR
tail возвращает все элементы списка, окромя первого:
tail :: [a] -> [a]
tail [1,2,3] ⇒ [2,3]
tail [3] ⇒ []
tail [] ⇒ ERROR
l,l ⇔ (head l):(tail l)evenSum возвращает сумму всех четных чисел в списке:
-- Версия 1
evenSum :: [Integer] -> Integer
evenSum l = accumSum 0 l
accumSum n l = 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 или let.accumSum не будет загрязнять глобальное пространство имен.
-- Версия 2
evenSum :: Integral a => [a] -> a
evenSum l = accumSum 0 l
where accumSum n l =
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
f x = (какое-то выражение) 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 принимает в качестве аргументов функцию типа (a -> Bool) и список типа [a]. Она возвращает список, содержащий только те элементы, для которых функция вернула true.foldl, которая позволяет аккумулировать значение. Функция foldl реализует популярный прием программирования:
myfunc list = foo initialValue list
foo accumulated [] = accumulated
foo tmpValue (x:xs) = foo (bar tmpValue x) xs
myfunc list = foldl bar initialValue list
foldl приведена ниже.
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
foldl f z [x1,...xn]
⇔ f (... (f (f z x1) x2) ...) xn
(f z x), а запихивает его в стек.foldl' вместо foldl;foldl' это строгая (или энергичная) реализация foldl.evenSum выглядит так:
-- Версия 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' (\x y -> x+y) 0 (filter even l)
(\x y -> x+y) ⇔ (+)
-- Версия 8
import Data.List (foldl')
evenSum :: Integral a => [a] -> a
evenSum l = foldl' (+) 0 (filter even l)
foldl' не самая интуитивно понятная функция. Но с ней обязательно стоит разобраться.
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 (h x))
-- Версия 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. Например:
% 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 a a
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) станет деревом, в котором:xxs строго меньших 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 aShow.
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 x l r) = Node (x-1) (dec l) (dec r)
inc (Node x l r) = 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 (f x)
(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
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
комментарии (50)