Haskell

Thành phần chức năng là quá trình sử dụng đầu ra của một chức năng như một đầu vào của chức năng khác. Sẽ tốt hơn nếu chúng ta học toán học đằng sau cấu tạo . Trong toán học, thành phần được ký hiệu là f {g (x)} trong đó g () là một hàm và đầu ra của nó được sử dụng làm đầu vào của một hàm khác, nghĩa là f () .

Thành phần chức năng có thể được thực hiện bằng cách sử dụng hai chức năng bất kỳ, miễn là kiểu đầu ra của một chức năng phù hợp với kiểu đầu vào của chức năng thứ hai. Chúng tôi sử dụng toán tử dấu chấm (.) Để triển khai thành phần hàm trong Haskell. Hãy xem đoạn mã ví dụ sau. Ở đây, chúng tôi đã sử dụng thành phần hàm để tính toán xem một số đầu vào là chẵn hay lẻ

eveno :: Int -> Bool 
noto  :: Bool -> String 

eveno x = if x `rem` 2 == 0 
   then True 
else False 
noto x = if x == True 
   then "This is an even Number" 
else "This is an ODD number" 

main = do 
   putStrLn "Example of Haskell Function composition" 
   print ((noto.eveno)(16))

Ở đây, trong hàm chính , chúng ta đang gọi đồng thời hai hàm, noto và eveno . Đầu tiên, trình biên dịch sẽ gọi hàm “eveno ()” với 16 làm đối số. Sau đó, trình biên dịch sẽ sử dụng đầu ra của phương thức eveno làm đầu vào của phương thức noto () .

Đầu ra của nó sẽ như sau:

 Example of Haskell Function composition              

 “This is an even Number”

Vì chúng ta đang cung cấp số 16 làm đầu vào (là một số chẵn), hàm eveno () trả về true , trở thành đầu vào cho hàm noto () và trả về đầu ra: “Đây là một số chẵn”.

Haskell - Mô-đun

Nếu bạn đã làm việc trên Java, thì bạn sẽ biết cách tất cả các lớp được liên kết vào một thư mục được gọi là gói . Tương tự, Haskell có thể được coi là một tập hợp các mô-đun .

Haskell là một ngôn ngữ chức năng và mọi thứ được biểu thị dưới dạng một biểu thức, do đó một Mô-đun có thể được gọi là một tập hợp các loại chức năng tương tự hoặc có liên quan.

Bạn có thể nhập một chức năng từ một mô-đun này vào một mô-đun khác. Tất cả các câu lệnh “nhập” phải xuất hiện đầu tiên trước khi bạn bắt đầu xác định các hàm khác. Trong chương này, chúng ta sẽ tìm hiểu các tính năng khác nhau của các mô-đun Haskell.

Mô-đun danh sách

Danh sách cung cấp một số chức năng tuyệt vời để làm việc với dữ liệu kiểu danh sách . Khi bạn nhập mô-đun Danh sách, bạn có nhiều chức năng theo ý của mình. Trong ví dụ sau, chúng tôi đã sử dụng một số chức năng quan trọng có sẵn trong mô-đun Danh sách.

import Data.List  

main = do  
   putStrLn("Different methods of List Module") 
   print(intersperse '.' "Tutorialspoint.com") 
   print(intercalate " " ["Lets","Start","with","Haskell"]) 
   print(splitAt 7 "HaskellTutorial") 
   print (sort [8,5,3,2,1,6,4,2])

Ở đây, chúng ta có nhiều chức năng mà không cần xác định chúng. Đó là bởi vì các chức năng này có sẵn trong mô-đun Danh sách. Sau khi nhập mô-đun Danh sách, trình biên dịch Haskell làm cho tất cả các chức năng này khả dụng trong không gian tên chung. Do đó, chúng tôi có thể sử dụng các chức năng này. Mã của chúng tôi sẽ mang lại kết quả sau:

Different methods of List Module
"T.u.t.o.r.i.a.l.s.p.o.i.n.t...c.o.m"
"Lets Start with Haskell"
("Haskell","Tutorial")
[1,2,2,3,4,5,6,8]

Mô-đun Char

Các Char mô-đun có rất nhiều chức năng được xác định trước để làm việc với các loại nhân vật. Hãy xem khối mã sau:

import Data.Char 

main = do  
   putStrLn("Different methods of Char Module") 
   print(toUpper 'a') 
   print(words "Let us study tonight") 
   print(toLower 'A')

Ở đây, các chức năng toUpper và toLower đã được xác định bên trong mô-đun Char . Nó sẽ tạo ra kết quả sau:

Different methods of Char Module
'A'
["Let","us","study","tonight"]
'a'

Mô-đun bản đồ

Bản đồ là kiểu dữ liệu kiểu cặp giá trị gia tăng không được sắp xếp. Nó là một mô-đun được sử dụng rộng rãi với nhiều chức năng hữu ích. Ví dụ sau đây cho thấy cách bạn có thể sử dụng một chức năng được xác định trước có sẵn trong mô-đun Bản đồ.

import Data.Map (Map) 
import qualified Data.Map as Map  --required for GHCI  

myMap :: Integer -> Map Integer [Integer] 
myMap n = Map.fromList (map makePair [1..n]) 
   where makePair x = (x, [x])  

main = print(myMap 3)

Nó sẽ tạo ra kết quả sau:

fromList [(1,[1]),(2,[2]),(3,[3])]

Đặt mô-đun

Mô-đun Set có một số chức năng được xác định trước rất hữu ích để thao tác với dữ liệu toán học. Một tập hợp được thực hiện dưới dạng cây nhị phân, vì vậy tất cả các phần tử trong một tập hợp phải là duy nhất. Hãy xem đoạn mã ví dụ sau

import qualified Data.Set as Set   

text1 = "Hey buddy"   
text2 = "This tutorial is for Haskell"   

main = do  
   let set1 = Set.fromList text1   
       set2 = Set.fromList text2 
   print(set1) 
   print(set2)

Ở đây, chúng tôi đang sửa đổi một Chuỗi thành một Tập hợp. Nó sẽ tạo ra kết quả sau. Quan sát rằng tập hợp đầu ra không có sự lặp lại của các ký tự

fromList " Hbdeuy"
fromList " HTaefhiklorstu"

Hãy xem cách chúng ta có thể tạo một mô-đun tùy chỉnh có thể được gọi ở các chương trình khác. Để triển khai mô-đun tùy chỉnh này, chúng tôi sẽ tạo một tệp riêng có tên “custom.hs” cùng với “main.hs” của chúng tôi .

Hãy để chúng tôi tạo mô-đun tùy chỉnh và xác định một vài chức năng trong đó.custom.hs

module Custom ( 
   showEven, 
   showBoolean 
) where 

showEven:: Int-> Bool 
showEven x = do 

if x 'rem' 2 == 0 
   then True 
else False 
showBoolean :: Bool->Int 
showBoolean c = do 

if c == True 
   then 1 
else 0

Mô-đun tùy chỉnh của chúng tôi đã sẵn sàng. Bây giờ, chúng ta hãy nhập nó vào một chương trình.

main.hs

import Custom 

main = do 
   print(showEven 4) 
   print(showBoolean True)

Mã của chúng tôi sẽ tạo ra kết quả sau: True 1

Hàm showEven trả về giá trị True , vì “4” là số chẵn. Hàm showBoolean trả về “1” vì hàm Boolean mà chúng ta đã truyền vào hàm là “True”.

Haskell – Đầu vào & Đầu ra

Tất cả các ví dụ mà chúng ta đã thảo luận cho đến nay đều có bản chất tĩnh. Trong chương này, chúng ta sẽ học cách giao tiếp động với người dùng. Chúng ta sẽ học các kỹ thuật đầu vào và đầu ra khác nhau được sử dụng trong Haskell.

Tệp và Luồng

Cho đến nay, chúng tôi đã mã hóa cứng tất cả các đầu vào trong chính chương trình. Chúng tôi đã lấy đầu vào từ các biến tĩnh. Bây giờ, chúng ta hãy tìm hiểu cách đọc và ghi từ một tệp bên ngoài.

Hãy để chúng tôi tạo một tệp và đặt tên là “abc.txt”. Tiếp theo, nhập các dòng sau vào tệp văn bản này: “Chào mừng bạn đến với Tutorialspoint. Tại đây, bạn sẽ nhận được tài nguyên tốt nhất để học Haskell.”

Tiếp theo, chúng ta sẽ viết đoạn mã sau để hiển thị nội dung của tệp này trên bảng điều khiển. Ở đây, chúng ta đang sử dụng hàm readFile () để đọc một tệp cho đến khi nó tìm thấy một ký tự EOF.

main = do  
   let file = "abc.txt" 
   contents <- readFile file 
   putStrLn contents 

Đoạn mã trên sẽ đọc tệp “abc.txt” dưới dạng Chuỗi cho đến khi nó gặp bất kỳ ký tự Cuối tệp nào. Đoạn mã này sẽ tạo ra kết quả sau.

Welcome to Tutorialspoint
Here, you will get the best resource to learn Haskell.

Quan sát rằng bất cứ thứ gì nó đang in trên thiết bị đầu cuối đều được ghi trong tệp đó.

Đối số dòng lệnh

Haskell cũng cung cấp cơ sở để vận hành một tệp thông qua dấu nhắc lệnh. Hãy để chúng tôi quay lại thiết bị đầu cuối và nhập “ghci” . Sau đó, nhập nhóm lệnh sau:

let file = "abc.txt" 
writeFile file "I am just experimenting here." 
readFile file

Ở đây, chúng tôi đã tạo một tệp văn bản có tên “abc.txt”. Tiếp theo, chúng tôi đã chèn một câu lệnh trong tệp bằng lệnh writeFile . Cuối cùng, chúng ta đã sử dụng lệnh readFile để in nội dung của tệp trên bảng điều khiển. Mã của chúng tôi sẽ tạo ra kết quả sau:

I am just experimenting here.

Ngoại lệ

Một ngoại lệ có thể được coi là một lỗi trong mã. Đó là một tình huống mà trình biên dịch không nhận được đầu ra mong đợi trong thời gian chạy. Giống như bất kỳ ngôn ngữ lập trình tốt nào khác, Haskell cung cấp một cách để thực hiện xử lý ngoại lệ.

Nếu bạn đã quen thuộc với Java, thì bạn có thể biết khối Try-Catch, nơi chúng ta thường phát hiện ra một lỗi và bắt giống nhau trong khối catch . Trong Haskell, chúng ta cũng có chức năng tương tự để bắt lỗi thời gian chạy.

Định nghĩa hàm của try trông giống như “try :: Exception e => IO a -> IO (Either ea)”. Hãy xem đoạn mã ví dụ sau. Nó chỉ ra cách bạn có thể bắt được ngoại lệ “Chia cho 0”.

Ở đây, chúng tôi đã tạo một tệp văn bản có tên "abc.txt". Tiếp theo, chúng tôi đã chèn một câu lệnh trong tệp bằng lệnh writeFile . Cuối cùng, chúng ta đã sử dụng lệnh readFile để in nội dung của tệp trên bảng điều khiển. Mã của chúng tôi sẽ tạo ra kết quả sau:
I am just experimenting here.
Ngoại lệ
Một ngoại lệ có thể được coi là một lỗi trong mã. Đó là một tình huống mà trình biên dịch không nhận được đầu ra mong đợi trong thời gian chạy. Giống như bất kỳ ngôn ngữ lập trình tốt nào khác, Haskell cung cấp một cách để thực hiện xử lý ngoại lệ.
Nếu bạn đã quen thuộc với Java, thì bạn có thể biết khối Try-Catch, nơi chúng ta thường phát hiện ra một lỗi và bắt giống nhau trong khối catch . Trong Haskell, chúng ta cũng có chức năng tương tự để bắt lỗi thời gian chạy.
Định nghĩa hàm của try trông giống như "try :: Exception e => IO a -> IO (Either ea)". Hãy xem đoạn mã ví dụ sau. Nó chỉ ra cách bạn có thể bắt được ngoại lệ "Chia cho 0".
import Control.Exception 

main = do 
   result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int) 
   case result of 
      Left ex   -> putStrLn $ "Caught exception: " ++ show ex 
      Right val -> putStrLn $ "The answer was: " ++ show val 

Trong ví dụ trên, chúng tôi đã sử dụng hàm try có sẵn của mô-đun Control.Exception , do đó chúng tôi đang bắt trước ngoại lệ. Đoạn mã phía trên sẽ mang lại kết quả bên dưới trong màn hình.

Caught exception: divide by zero

Haskell – Functor (xem thêm)

Trả lời