Hàm tạo thông minh
https://wiki.haskell.org/Smart_constructors
Hàm tạo thông minh là một kỹ thuật trong Haskell nhằm kiểm soát các tham số đầu vào khi khởi tạo một kiểu dữ liệu bằng cách ẩn đi các constructor mặc định và cung cấp các hàm đặc biệt để thực hiện việc xây dựng. Chúng có thể được phân loại thành hai nhóm: kiểm tra tại thời điểm chạy và kiểm tra tại thời điểm biên dịch.
Ví dụ
{-# LANGUAGE FlexibleInstances #-}
module Resistor (
Resistor, -- trừu tượng, ẩn các constructor
metalResistor1, -- cách duy nhất để tạo ra điện trở kim loại
metalResistor2, -- cách duy nhất để tạo ra điện trở kim loại
Resistor3, -- trừu tượng, ẩn các constructor
resistor3, -- cách duy nhất để tạo ra điện trở kim loại
) where
import Control.Exception(assert)
-- kiểm tra tại thời điểm chạy
data Resistor = Metal Bands
| Ceramic Bands
deriving Show
type Bands = Int
metalResistor1 :: Bands -> Resistor
metalResistor1 n | n < 4 || n > 8 = error "Số lượng dải điện trở không hợp lệ"
| otherwise = Metal n
metalResistor2 :: Bands -> Resistor
metalResistor2 n = assert (n >= 4 && n <= 8) $ Metal n
-- kiểm tra tại thời điểm biên dịch
data Z = Z
data S a = S a
class Card c where
instance Card Z where
instance (Card c) => Card (S c) where
class Card size => InBounds size where
instance InBounds (S (S (S (S Z)))) where -- bốn
instance InBounds (S (S (S (S (S Z))))) where -- năm
instance InBounds (S (S (S (S (S (S Z)))))) where -- sáu
instance InBounds (S (S (S (S (S (S (S Z))))))) where -- bảy
instance InBounds (S (S (S (S (S (S (S (S Z)))))))) where -- tám
d0 = undefined :: Z
d3 = undefined :: S (S (S Z))
d4 = undefined :: S (S (S (S Z)))
d6 = undefined :: S (S (S (S (S (S Z)))))
d8 = undefined :: S (S (S (S (S (S (S (S Z)))))))
d10 = undefined :: S (S (S (S (S (S (S (S (S (S Z)))))))))
data Resistor3 size = Resistor3 deriving Show
resistor3 :: InBounds size => size -> Resistor3 size
resistor3 _ = Resistor3
Kiểm tra tại thời điểm chạy
*Resistor> metalResistor1 4
Metal 4
*Resistor> metalResistor2 7
Metal 7
*Resistor> metalResistor1 9
*** Exception: Số lượng dải điện trở không hợp lệ
CallStack (from HasCallStack):
error, called at smart_constructors.hs:18:37 in main:Resistor
*Resistor> metalResistor2 0
*** Exception: Assertion failed
CallStack (from HasCallStack):
assert, called at smart_constructors.hs:22:20 in main:Resistor
Kiểm tra tại thời điểm biên dịch
*Resistor> resistor3 d0
<interactive>:15:1: error:
• No instance for (InBounds Z) arising from a use of ‘resistor3’
• In the expression: resistor3 d0
In an equation for ‘it’: it = resistor3 d0
*Resistor> resistor3 d3
<interactive>:16:1: error:
• No instance for (InBounds (S (S (S Z))))
arising from a use of ‘resistor3’
• In the expression: resistor3 d3
In an equation for ‘it’: it = resistor3 d3
*Resistor> resistor3 d4
Resistor3
*Resistor> :t resistor3 d4
resistor3 d4 :: Resistor3 (S (S (S (S Z))))
*Resistor> resistor3 d6
Resistor3
*Resistor> resistor3 d8
Resistor3
*Resistor> :t resistor3 d8
resistor3 d8 :: Resistor3 (S (S (S (S (S (S (S (S Z))))))))
*Resistor> resistor3 d10
<interactive>:22:1: error:
• No instance for (InBounds
(S (S (S (S (S (S (S (S (S (S Z)))))))))))
arising from a use of ‘resistor3’
• In the expression: resistor3 d10