ghi chú học Haskell (98): Các hàm tạo thông minh

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

Thẻ: Haskell smart constructors functional programming Type Safety Data Abstraction

Đăng vào ngày 5 tháng 6 lúc 23:44