Haskell #1: Haskell-Thực hành-1

Ở bài 1 chúng ta đã đọc qua, bây giờ chúng ta sẽ áp dụng những gì đã học như cài đặt ngôn ngữ, trình soạn code và áp dụng những phương thức trong bài 1 xem chúng hoạt động thế nào. Có thể bài đó bạn đọc sẽ khó hiểu vậy có thể thực hành ngay tại đây nhưng bạn đọc cần phải nắm những phần cơ bản như haskell là ngôn ngữ lập trình hàm, lazy, statically type...

1. Cài đặt trình soạn code

Để viết code chúng ta cần trình soạn thảo. Ở đây sẽ dùng visual studio code bạn đọc có thể vào trang chủ của nó tuỳ vào hệ điều hành của bạn đọc mà tải về, vào biểu tượng bên trái tìm với từ khoá "haskell" cài hai thư viện cuối cùng, 1 màu code, 2 gợi ý code





2. Cài đặt Haskell

Có vài thuật ngữ bạn đọc cần nắm rõ như GHC trình biên dịch, cabal dùng để quản lý phần mềm haskell nó như pip trong python, composer trong PHP..., stack dùng để phát triên đa nền tảng

Nếu quý bạn đọc dùng hệ điều hành ubuntu, window có thể tham khảo: link

Trong bài này sẽ cài đặt trên Mac và hướng dẫn trên Mac, mở terminal và pass đoạn sau để cài đặt

brew install cabal-install

Vậy là đã cài đặt xong, tại terminal quý bạn đọc gõ ghci và thử 2 + 2 nếu ra kết quả vậy chúc mừng bạn đọc thành công giai đoạn đầu

3. Tạo project

Quý bạn đọc mở lên sẽ có hướng dẫn chi tiết nhưng quý bạn đọc có thể làm coppy và gán vaò termianl 

<pre>mkdir myfirstapp 
cd myfirstapp 
cabal init --cabal-version=2.4 --license=NONE -p myfirstapp 
cabal run </pre/

Nếu có kết quả vậy đã thành công bậy giờ cần mở project xem chúng có những gì


app/Main.hs nơi chúng ta sẽ viết code, gõ nhưng đoạn này vào





myfirstapp.cabal nơi chứa mô tả dự án cũng nhu khai báo thư viện(dependencies) và sau đây chúng ta thêm một thư viện mới haskell-say ^>=1.0.0.0


Sau đó tại terminal của dự án gõ: cabal run chúng ta sẽ thấy điều khác biệt

4. Mở project vừa tạo và thực hành

Ở file Main.hs quý đọc giả sửa lại sau để dễ dàng thực hành


5. Thực hành với các phương thức

Quý bạn đọc mở file Main.hs chúng ta sẽ thực hành tại đây và mở thêm teminal sau khi viết một phương thức mới ta sẽ chạy lên xem chúng hoạt động thế nào(control + ~)

5.1. succ: nhận vào thứ gì đó và trả về kết quả kế tiếp(pred ngược lại)



5.2. min, max nhận vào thứ có thể sắp xếp được


5.3 List

Khai báo: let count_numbers  = [1,2,5,3,8] đây là mảng số hoặc ['a','t'] mảng string không được vừa số vừa chữ nhé 
++  nối hai mảng: [2,4,6] ++ [1,4,5]=[2,4,6,1,4,5] hoặc ['h','a','s'] ++ ['k','e','l','l']="haskell"
: có thể nối mảng chỉ có 1 phần tử ở đầu: 3:[3,5]=[3,3,5]
!! lấy phần tử với một chỉ số nhất định: haskell !! 1 hoặc [3,5,7,2] !! 1=5
">" "<" "==" có thể dùng các toán tử để so sánh 2 mảng và chúng so sánh từ trái sang phải: [1,3]>[0,3]=True
head nhận vào một list trả về kết quả đầu tiên: head [2,4,6]=2
tail sẽ chặt phần đầu của mảng đi: tail [3,5,2]=[5,2]
last sẽ trả về phần tử cuối cùng: last [3,5]=5
init loại phần tử cuối cùng của mảng: init [5,3,8]=[5,3]
length trả về độ dài của mảng: length: [4,7,8]=3
null xem list có rỗng không: null [] = True
reverse đảo ngược mảng: reverse [4,3,9]=[9,3,4]
take nhận vào một số n là integer và một mảng trả về n phần tử kể từ đầu list: take 2 [2,4,1,8] = [2,4]
drop như take nhưng ngược lại bỏ đi n phần tử kể từ đầu list: drop 2 [2,5,1,9,3]=[1,9,3]
minimum: trả về phần tử nhỏ nhất của list: minimum [2,4,1]=1
maximum: trả về phần tử lớn nhất của list: maximum [3,4,5]=5
sum: nhận vào list trả về tổng của chúng: sum [3,5,1]=9
product: nhận vào list trả về tích của chúng: product [1,2,5]=10
elem nhận vào thứ gì đó xem chúng có thuộc list không: 2 `elem` [3,2,1]=True
notElem thì ngược lại với elem
range: tạo ra mảng trong phạm vi: [1..20], ['a'...'z'], có thể nhận số bước nhảy: [2,4..10]=[2,4,6,8,10], [20,19..17]=[20,19,18,17]
cycle nhận vào list rồi lặp vô hạn nên dùng take để dừng lại: take 10 (cycle [1,2,3]) = [1,2,3,1,2,3,1,2,3,1], take 2 (cycle ['I'])=["I","I"]
repeat nhận vào một số sau đó lặp vô hạn: repeat 3 nên dùng take để dừng lại
replicate nhận vào số lần lặp và số cần lặp: replicate 3 10 = [10,10,10]
list comprehention: cho ra một tập hợp cụ thể từ tập hợp tổng quát. ta sẽ có comprehention cơ bản {2x | x thuộc n, x <=10}, phía trước | là kết quả trả về với x thuộc tập hợp và với điều kiện x <=10
- Như trên ta viết thành [2*x | x <- [1..10]]=[2,4,6,8,10,12,14,16,18,,20] (ta đã học [1..10] là range 1 đến 10 môĩ lần như vậy sẽ nhân 2
- Ta có thêm điều kiện [2*x | x <- [1..10], x < 5]= [2,4,6,8] (cũng như trên nhưng khi từ 1 đến 4 đã dừng lại
- Ta có comprehention nâng cao hơn result sx = [if x < 5 then "YEU" else "GHET" | x <- sx, odd x]: Ta sẽ có mảng với x < 5 là YEU ngược lại là GHET, x thuộc sx với điều kiện là số lẻ, odd cho ra true khi x là số lẻ


- Ta có thể loại trừ những thứ ta không muốn [x | x <- [9..14], x/=10, x/=13]=[9,11,12,14]
- Ta có thể xoá hết phần tử chỉ còn từ a -> z


5.4 Tuple


Cũng giống list cho phép lưu nhiều giá trị nhưng có thể chứa kiểu số hay cả kiểu chuỗi: ("Tuoi", "Ten", 12)
fst nhận cặp trả về phất tử thứ nhất: fst (2,4)=2
snd nhận vào một cặp trả về phần tử thứ hai: snd (2,1)=1
zip nhận vào hai mảng trả về mảng tuple
. zip [1,4,2] [2,5,3]=[(1,2),(4,5),2,3)]
. zip [1..5] ["a","b"]=[(1,"a"),(2,"b")]

zipWith lấy hai danh sách và áp dụng một hàm cho từng cặp phần tử, tạo ra một danh sách có cùng độ dài với độ dài ngắn hơn của hai phần tử:
 ghci> zipWith (+) [1,2,3] [4,5,6]=[5,7,9]

5.5 Các hàm mở rộng


Hàm isInfixOfisSuffixOf khớp với bất kỳ vị trí nào trong danh sách và ở cuối của nó, còn isPrefixOf cho biết đối số bến trái khớp với phần đầu của đối số bên phải không
ghci> :module + Data.List
ghci> "foo"  `isInfixOf` "foobar" = True
ghci> [2,4] `isInfixOf` [3,1,4,1,5,2,6,5,3,9]=True
ghci> "end" `isSuffixOf` "the end" = True
ghci> "foo" `isPrefixOf` "foobar" = True
ghci> [1,2] `isPrefixOf` [] = False

concat nhận một danh sách các danh sách, tất cả đều cùng loại và nối chúng thành một danh sách duy nhất:
ghci> concat [[1,2,3],[4,5,6]]=[1,2,3,4,5,6]

odd trả về True nếu list hoặc số bất kỳ là số lẻ
ghci> odd 3 = True
even trả về True nếu list hoặc số bất kỳ là số chẵn
ghci> even 2 = True

all trả về True nếu điều kiện đó thỏa mãn trên mọi phần tử của danh sách, trong khi any trả về True nếu điều kiện đó thỏa mãn trên ít nhất một phần tử của danh sách:
ghci> all odd [1,3,5]=True
ghci> any odd [1,2,5]=True

Hàm splitAt kết hợp các hàm take và drop, trả về một cặp danh sách đầu vào, tách theo chỉ mục nhất định
ghci> splitAt 3 "foobar" = ("foo","bar")

takeWhiledropWhile nhận các điều kiện. takeWhile lấy các phần tử từ đầu danh sách miễn là điều kiện trả về True, trong khi dropWhile loại bỏ các phần tử khỏi danh sách miễn là điều kiện trả về True
ghci> takeWhile odd [1,3,5,6,8,9,11]=[1,3,5]
ghci> dropWhile even [2,4,6,3,7,2]=[3,7,2]

span, break như splitAt tạo ra tuple nhưng thoả mãn điều kiện, break sẽ cắt phần đầu khi điều kiện là False
ghci> span even [2,4,6,7,10,11]=([2,4,6],[7,10,11])
ghci> break even [1,3,5,6,8,9,10]=([1,3,5],[6,8,9,10])
ghci> break odd [2,4,5,6,8]=([2,4],[5,6,8])
ghci> break isUpper "isUpper" = ("is","Upper")

lines, unlines tách văn bản
ghci> lines "foo\nbar"=["foo","bar"]
ghci> unlines ["foo","bar"]="foo\nbar\n"

words, unwords cắt khoảng trằng và dùng khoảng trắng duy nhất để nối chuỗi
ghci>words "the hasekll learn" = ["the","haskell","learn"]
ghci>unwords ["the","haskell","learn"]="the haskell learn"

toLower, toUpper chuyển chữ hoa thành thường và ngược lại(:module +Data.Char)
negate chuyển số âm thành dương nếu đầu vào là số âm còn ngược lại

intersperse nhận một phần tử và list rồi áp dụng giữa các phần tử trong list
ghci> intersperse 0 [1,2] = [1,0,2]

transpose hoán vị danh sách của danh sách, các cột thành các dòng
ghci> transpose [[1,2], [3,4]] = [[1,3], [2,4]]
ghci> transpose ["ab", "cd"] = ["ac", "bd"]
ghci> map sum $ transpose [[0,3,5,9],[10,0,0,9],[8,5,1,-1]] = [18,8,6,17] 

concat làm giảm bớt một danh sách
ghci> concat ["foo","bar","car"] = "foobarcar"

http://learnyouahaskell.com/modules#loading-modules