Небольшая предыстория о том, как начал программировать на Haskell-е
Среда
После встречи piter.rb#4 (в позапрошлую среду) познакомился через докладчиков с языком Haskell. Язык показался интересным для изучения и непонятным, с точки зрения применения. Т. е. нахрена он нужен.
Четверг
Почитал на wikipedia, на паре других ресурсах... меня терзало
Пятница
Невыдержал. Установил компилятор GHC. Накачал книжек в pdf формате. И покодил (вместо телевизара и прсомотра фильмов с торрентов). Да, я отказался от просмотра последних филтьмов с торрентов и просмотра передач с канала Discavery в пользу программирования на Haskell. На Haskell - как основной язык программирования не подсел - так чисто любительское.
Суббота
Меня осенило. Haskell чудокават, но в полне по силам его освоить. Ребята (Дронов к примеру) не так позиционирует язык. Многие термины используемые в программировании Haskell не являются чем-то не знакомым обычным (особенно после внятной расшифровки) программистам императивщикам.
Сегодня
Неделю спустя, все еще программирую на запале интереса...
Объективные "-" компилятора ghc (так как он единственный для языка то и языка )
- Довольно объемный исполняемый файл ~ 1 Mb,
- Быстрой работы пока не заметил.
Самокритика объективных "-"
- А нужна ли эффективность-быстродействие программы?
Для практики написал программу с реализацией на Haskell алгоритма подсчета определителя матрицы, перемножения двух матриц. Функцию транспонирования матриц на Haskell позаимствовал в рунете:
main=do
print "Matrix detrminant:"
print (matrixDet [[1,2,3],[7,5,6],[7,8,9]])
print (matrixDet [[1,2],[4,5]])
print (matrixDet [[1]])
print (matrixDet [[]])
print $ matrixDet [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
print $ matrixDet [[7,4,6,0],[3,1,2,4],[9,7,2,3],[1,5,8,2]]
print $ matrixDet [[(-7.9),4.1,6.7,0],[3,1,2,4],[9,7,2.3,3],[1,5,8,2]]
print "Get row & column:"
print $ getRow [[1,2,3],[4,5,6],[7,8,9]] 1
print $ getColumn [[1,2.9,3.0],[4,5.7,6],[7,8,9]] 1
print "Multiplication of lists:"
print $ sum $ map (\(x,y) -> x*y) (zip [1,2,3] [3,0,6])
print $ sum $ zipWith (*) [1,2,3] [3,0,6]
print $ sum $ zipWith (*) [1,2,3] [3,0]
print "Matrix transponation:"
print $ matrixTransp [[1,2,3],[1,2,3]]
print $ transp [[1,2,3],[1,2,3]]
print "matrix mult:"
print $ matrMult [[1,2,3],[7,9,8]] [[8,7],[5,4],[1,0]]
print $ matrMult [[1,2,3],[7,9,8]] [[5],[6],[7]]
print $ matrixDet $ matrMult [[1,2,3],[7,9,8]] [[8,7],[5,4],[1,0]]
-- Функция подсчета определителя матрицы
matrixDet [[]] = 0
matrixDet [[x]] = x
matrixDet [[x1, x2], [x3, x4]] = x1*x4 - x2*x3
matrixDet m = let row = head m in
sum (indexMap (\(x,i)->x*(znakFunc i)*(matrixDet (minor m 0 i))) row)
where
znakFunc x = if x`mod`2==0 then 1 else (-1) -- (-1)^(i+j), i=0, j=0..
-- перебор списка с индексом, \(x,i) -> ... , but i is Enum
indexMap _func _list = map _func (zip _list [0..])
-- фильтрация списка с учетом индекса элемента в списке:
indexFilter _func _array = map (\x -> fst x) (filter _func (zip _array [0..]))
-- функция определения матрицы минора
minor :: (Num a, Integral b) =>[[a]] -> b ->b -> [[a]]
minor matrix _i _j = map (\row -> indexFilter (\(_,j)->not(j==_j)) row)
(indexFilter (\(_,i)-> not(i==_i) ) matrix)
-- примитив: функция для извлечения строки
getRow :: (Integral b, Num a) => [[a]] -> b -> [a]
getRow m i = (m!!(fromEnum i))
-- примитив: функция для извлечения вектора
getColumn :: (Integral b, Num a) => [[a]] -> b -> [a]
getColumn m j = map (\row -> row!!(fromEnum j) ) m
-- 1-й вариант транспонирования матрицы:
matrixTransp :: [[a]] -> [[a]]
matrixTransp m = [[m!!i!!j| i<-[0..((length m)-1)]] |j<-[0..(length(m!!0)-1)]]
-- 2-й вариант транспонирования матрицы. Определение транспонированной матрицы через рекурсию:
-- транспонированная матрица - это такая матрица, первая строка которой равна
-- первому столбцу исходной, а остаток равен траспонированному остатку исходной
transp ([]:_) = []
transp m = map head m: transp (map tail m)
-- Функция перемножения двух матриц
matrMult :: (Num m)=> [[m]]->[[m]]->[[m]]
matrMult m1 m2= let _m2 = (transp m2) in
map (\r1-> (map (\c2-> sum(zipWith(*) r1 c2)) _m2 )) m1
-- Здесь чтобы во второй матрице не извлекать вектор (строку у добнее)
-- вторую матрицу просто транспонируем в _m2