2010-01-15 33 views
8

Giả sử tôi có một nguyên mẫu chức năng như sau:số nguyên không âm

func :: [Int] -> [Int] 

Làm thế nào là nó có thể để thực thi chỉ một danh sách không tiêu cực của số nguyên như các đối số đầu vào? Tôi sẽ phải thay đổi loại param từ [Int] thành cái gì ..? Tại thời điểm hợp lý này, nó hoạt động với func [-1, -2], tôi chỉ muốn nó hoạt động với [1,2] tức là với thông dịch viên phát tán thông báo lỗi.

Trả lời

4
+0

Tôi hy vọng rằng ai đó sẽ hiển thị như thế nào để làm điều này với các loại, nhưng bây giờ tôi có thể thấy rằng đây là điều không thể - từ những nhận xét cho lớp loại NonNegative.C không âm: "Trường hợp của lớp này phải đảm bảo giá trị không âm. Chúng tôi không thể thực thi điều này theo loại, nhưng ràng buộc loại lớp NonNegative.C tránh sử dụng ngẫu nhiên các loại cho phép số âm." Thật thất vọng :-) – liwp

1

Bạn có thể sử dụng Peano numbers, thay đổi loại chức năng của bạn thành [Peano] -> .... Nhưng sau đó bạn sẽ phải thêm chức năng chuyển đổi từ số nguyên thành số peano và quay lại bất cứ khi nào bạn gọi hàm của mình.

Hoặc bạn có thể thêm một tấm séc runtime:

func xs 
    | any (< 0) xs = error "only non-negative integers allowed as input" 
    | otherwise  = ... 

Lưu ý rằng giải pháp thứ hai làm cho chức năng của bạn strict.

7
newtype NonNegative a = NonNegative a 

toNonNegative :: (Num a, Ord a) => a -> NonNegative a 
toNonNegative x 
    | x < 0 = error "Only non-negative values are allowed." 
    | otherwise = NonNegative x 

fromNonNegative :: NonNegative a -> a 
fromNonNegative (NonNegative x) = x 

Chỉ cần cẩn thận để không bao giờ sử dụng hàm tạo NonNegative trực tiếp. Điều này sẽ dễ dàng hơn nếu bạn đặt nó vào một mô-đun riêng và không xuất nó.

Ngoài ra, bây giờ bạn có thể sử dụng (ánh xạ tớiNonNegative) để chuyển đổi một cách lười biếng danh sách số.

Điều này sẽ vẫn yêu cầu kiểm tra thời gian chạy bất cứ nơi nào bạn nhập số liệu thô.

Hoặc, bạn có thể sử dụng Data.Word.

0

Trong gói cơ bản với phiên bản> = 4.8.0.0, được bao gồm trong GHC 7.10.1 trở lên, hiện nay là một loại Natural mà làm những gì bạn muốn - bạn chỉ có thể thay đổi mã của bạn để:

import Numeric.Natural (Natural) 

func :: [Natural] -> [Int] 

Tuy nhiên, gần với Integer hơn Int, vì như Integer và không giống như Int, nó không có giá trị tối đa.

Natural, như Integer, là một thể hiện của NumIntegral, tất cả các phép tính số học tương tự và chức năng chuyển đổi có sẵn như bạn nhận được với Integer. Các nỗ lực tính toán số âm Natural sẽ ném một số Underflow vào thời gian chạy, là ArithException. Ngoài ra, thuận tiện, bạn có thể tạo một Natural chỉ sử dụng một số nguyên theo nghĩa đen, mà không có một chuyển đổi:

GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help 
Prelude> :m +Numeric.Natural 
Prelude Numeric.Natural> 2 :: Natural 
2 

Tuy nhiên, nếu bạn muốn ở lại trong lĩnh vực số nguyên kích thước cố định, có một giải pháp cho điều đó, quá - và nó đã tồn tại lâu hơn - Word từ the module Data.Word (cũng chứa ví dụ Word8 đối với các số nguyên không âm 8 bit). Bạn sẽ sử dụng Word theo cách tương tự như Natural.Tuy nhiên, được cảnh báo - sự Word loại sẽ âm thầm underflow, mà không cần ném một ngoại lệ:

GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help 
Prelude> :m +Data.Word 
Prelude Data.Word> 2 :: Word 
2 
Prelude Data.Word> it - 4 
18446744073709551614 
Các vấn đề liên quan