Gần nhất tôi có thể nghĩ đến sẽ là một cái gì đó giống như
λ> data Bin = LSB | Zero Bin | One Bin
λ| -- deriving Show
Điều này làm cho nó có thể để xây dựng số nhị phân làm chỉ
λ> One . One . Zero . Zero . One . One $ LSB
One (One (Zero (Zero (One (One LSB)))))
Người ta cũng có thể tưởng tượng một chức năng giải mã làm việc trên nguyên tắc của (phiên bản tốt hơn được đề xuất bởi Ingo trong các ý kiến)
λ> let toInt :: (Integral a) => Bin -> a
λ| toInt = flip decode 0
λ| where decode :: (Integral a) => Bin -> a -> a
λ| decode LSB value = value
λ| decode (Zero rest) value = decode rest (2*value)
λ| decode (One rest) value = decode rest (2*value + 1)
Mà sau đó có thể được sử dụng để giải mã một số nhị phân thành một số nguyên.
λ> toInt (Zero . One . One . One . Zero . Zero . One $ LSB)
57
Khó khăn với những gì bạn muốn đạt được là bạn cần phải đọc số nhị phân "từ trong ra ngoài", hay như vậy để nói chuyện. Để biết giá trị của chữ số quan trọng nhất, bạn cần phải biết số lượng chữ số bạn có trong số đó. Nếu bạn viết các số nhị phân của mình bằng "ngược" - tức là chữ số ngoài cùng là chữ số ít quan trọng nhất, thì mọi thứ sẽ dễ xử lý hơn nhưng các con số sẽ nhìn ngược lại khi bạn tạo chúng và in chúng ra bằng cách sử dụng thể hiện mặc định của Show
.
Lý do đây không phải là vấn đề với số đơn là vì không có "chữ số có nghĩa nhỏ nhất" vì tất cả các chữ số có cùng giá trị, vì vậy bạn có thể phân tích số từ hai hướng và bạn sẽ nhận được kết quả tương tự.
Để hoàn chỉnh, đây là điều tương tự nhưng với chữ số ngoài cùng là chữ số có ý nghĩa nhất:
λ> data Bin = MSB | Zero Bin | One Bin
λ| -- deriving Show
Điều đó có vẻ khá nhiều như trước đây, nhưng bạn sẽ nhận thấy rằng khi các chức năng giải mã được triển khai,
λ> let toInt = flip decode (1,0)
λ| where
λ| decode (One rest) (pos, val) = decode rest (pos*2, val+pos)
λ| decode (Zero rest) (pos, val) = decode rest (pos*2, val)
λ| decode MSB (_, val) = val
Số được viết ngược!
λ> toInt (Zero . Zero . Zero . One . Zero . One $ MSB)
40
Tuy nhiên, điều này dễ xử lý hơn nhiều. Ví dụ, chúng ta có thể thêm hai số nhị phân trên cơ sở từng trường hợp. (Cảnh báo: rất nhiều trường hợp)
λ> let add a b = addWithCarry a b False
λ| where
λ| addWithCarry :: Bin -> Bin -> Bool -> Bin
λ| addWithCarry MSB MSB True = One MSB
λ| addWithCarry MSB MSB False = MSB
λ| addWithCarry MSB b c = addWithCarry (Zero MSB) b c
λ| addWithCarry a MSB c = addWithCarry a (Zero MSB) c
λ| addWithCarry (Zero restA) (Zero restB) False = Zero (addWithCarry restA restB False)
λ| addWithCarry (One restA) (Zero restB) False = One (addWithCarry restA restB False)
λ| addWithCarry (Zero restA) (One restB) False = One (addWithCarry restA restB False)
λ| addWithCarry (One restA) (One restB) False = Zero (addWithCarry restA restB True)
λ| addWithCarry (Zero restA) (Zero restB) True = One (addWithCarry restA restB False)
λ| addWithCarry (One restA) (Zero restB) True = Zero (addWithCarry restA restB True)
λ| addWithCarry (Zero restA) (One restB) True = Zero (addWithCarry restA restB True)
λ| addWithCarry (One restA) (One restB) True = One (addWithCarry restA restB True)
Tại thời điểm đó thêm hai số nhị phân là một làn gió:
λ> let forty = Zero . Zero . Zero . One . Zero . One $ MSB
λ| eight = Zero . Zero . Zero . One $ MSB
λ|
λ> add forty eight
Zero (Zero (Zero (Zero (One (One MSB)))))
Và quả thật vậy!
λ> toInt $ Zero (Zero (Zero (Zero (One (One MSB)))))
48
+1, chỉ dành cho tiêu đề :) –
Chương 9 của "Cấu trúc dữ liệu thuần túy chức năng" của Chris Okasaki xem "Đại diện số" với trọng tâm là số nhị phân. Có thể bạn có thể xem bản xem trước đủ tốt của sách bằng Google Sách để tìm hiểu một số gợi ý cho công việc liên quan. –