2010-12-29 21 views
15

Tôi dự kiến ​​mã sau không thành công với lỗi loại do vi phạm minBound và maxBound. Nhưng, như bạn có thể thấy, nó đi qua mà không gắn cờ một lỗi.Làm thế nào để bạn sử dụng kiểu chữ Bounded trong Haskell để xác định loại có phạm vi dấu chấm động?

{-# OPTIONS_GHC -XTypeSynonymInstances #-} 
module Main where 

type Probability = Float 
instance Bounded Probability where 
    minBound = 0.0 
    maxBound = 1.0 

testout :: Float -> Probability 
testout xx = xx + 1.0 

main = do 
    putStrLn $ show $ testout 0.5 
    putStrLn $ show $ testout (-1.5) 
    putStrLn $ show $ testout 1.5 

Trong Prelude tôi có được điều này

*Main> :type (testout 0.5) 
(testout 0.5) :: Probability 

Và tại dấu nhắc tôi có được điều này:

[~/test]$runhaskell demo.hs 
1.5 
-0.5 
2.5 

Rõ ràng tôi không tuyên bố Bounded đúng cách, và tôi chắc chắn tôi đang làm một cái gì đó sai cú pháp. Không có nhiều công cụ đơn giản trên Google về typeclasses bị ràng buộc, vì vậy mọi trợ giúp sẽ được đánh giá cao.

Trả lời

21

Đó không phải là những gì Bounded dành cho. Bounded a chỉ cần xác định các chức năng minBound :: amaxBound :: a. Nó không gây ra bất kỳ kiểm tra đặc biệt hoặc bất cứ điều gì.

Bạn có thể xác định loại bị chặn bằng cách sử dụng cái gọi là hàm tạo thông minh thông minh. Đó là:

module Probability (Probability) where 

newtype Probability = P { getP :: Float } 
    deriving (Eq,Ord,Show) 

mkP :: Float -> Probability 
mkP x | 0 <= x && x <= 1 = P x 
     | otherwise = error $ show x ++ " is not in [0,1]" 

-- after this point, the Probability data constructor is not to be used 

instance Num Probability where 
    P x + P y = mkP (x + y) 
    P x * P y = mkP (x * y) 
    fromIntegral = mkP . fromIntegral 
    ... 

Vì vậy, cách duy nhất để thực hiện một Probability là sử dụng mkP chức năng cuối cùng (điều này được thực hiện cho bạn khi bạn sử dụng các hoạt động số trao dụ Num của chúng tôi), trong đó kiểm tra rằng các đối số nằm trong phạm vi . Do danh sách xuất của mô-đun, bên ngoài mô-đun này là không thể xây dựng xác suất không hợp lệ.

Có lẽ không phải là hai lớp lót bạn đang tìm kiếm, nhưng tốt thôi.

Để có khả năng tương thích bổ sung, bạn có thể đưa ra chức năng này bằng cách tạo mô-đun BoundCheck thay vì `Xác suất. Giống như trên, ngoại trừ:

newtype BoundCheck a = BC { getBC :: a } 
    deriving (Bounded,Eq,Ord,Show) 

mkBC :: (Bounded a) => a -> BoundCheck a 
mkBC x | minBound <= x && x <= maxBound = BC x 
     | otherwise = error "..." 

instance (Bounded a) => Num (BoundCheck a) where 
    BC x + BC y = mkBC (x + y) 
    ... 

Vì vậy, bạn có thể nhận được chức năng bạn mong muốn được tạo sẵn cho bạn khi bạn đặt câu hỏi.

Để thực hiện việc này, bạn có thể cần phần mở rộng ngôn ngữ {-# LANGUAGE GeneralizedNewtypeDeriving #-}.

+0

Rất hữu ích, cảm ơn bạn rất nhiều. Một câu hỏi: bạn đặt một dấu ba chấm ("...") để xác định các cách khác nhau trong đó mkP và mkBC tương tác với các toán tử hiện có trên những thứ của kiểu Num. Tôi cho rằng mục đích của việc này là xác định toán tử số học cho những thứ của kiểu xác suất mà tiếp tục chạy đầu ra thông qua mkP để kiểm tra giới hạn. – ramanujan

+0

@ramanujan, vâng. Về cơ bản chỉ tiếp tục trong mô hình đó. – luqui

+0

Trong trường hợp bạn không biết tìm kiếm phương thức 'Num' ở đâu: http://hackage.haskell.org/packages/archive/base/4.2.0.2/doc/html/Prelude.html#t%3ANum – luqui

Các vấn đề liên quan