2010-01-15 3 views
8

Скажет у меня есть прототип функции следующим образом:неотрицательных целых числа

func :: [Int] -> [Int] 

Как можно провести в жизнь только неотрицательного список целых чисел в качестве входных аргументов? Мне пришлось бы изменить тип параметра из [Int] на что ..? В этот честный момент он работает с func [-1, -2], я хочу, чтобы он работал с [1,2], т. Е. С интерпретатором, извергающим сообщение об ошибке.

ответ

4
+0

Я надеялся, что кто-то показать, как сделать это с типами, но теперь я вижу, что это невозможно - из комментария к класс NonNegative.C в неотрицательном: «Экземпляры этого класса должны обеспечивать неотрицательные значения. Мы не можем применять это по типам, но ограничение класса типа NonNegative.C позволяет избежать случайного использования типов, которые допускают отрицательные числа». Какое разочарование :-) – liwp

1

Вы можете использовать Peano numbers, изменив тип своей функции на [Peano] -> .... Но тогда вам придется добавлять функции преобразования из целых чисел в числа peano и обратно, когда вы вызываете вашу функцию.

Или вы могли бы добавить проверку выполнения:

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

Обратите внимание, что последнее решение делает вашу функцию 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 

Просто будьте осторожны, чтобы никогда не использовать конструктор NonNegative напрямую. Это будет проще, если вы поместите это в отдельный модуль и не экспортируете его.

Кроме того, теперь вы можете использовать (map toNonNegative) для ленивого преобразования списка чисел.

Это все равно требует проверки времени выполнения, где вы вводите необработанные числа.

В качестве альтернативы вы можете использовать Data.Word.

0

В базовом пакете с версии> = 4.8.0.0, которая входит в GHC 7.10.1 и выше, в настоящее время тип Natural, который делает то, что вы хотите - вы можете просто изменить свой код:

import Numeric.Natural (Natural) 

func :: [Natural] -> [Int] 

это, однако, ближе к Integer чем Int, потому что, как и в отличие от IntegerInt, он не имеет максимальное значение.

Поскольку Natural, как Integer, является экземпляром Num и Integral, все те же арифметические операции и функции преобразования доступны, как вы получите с Integer. Попытки вычислить отрицательный Natural будут вызывать Underflow во время выполнения, что является ArithException. Кроме того, удобно, вы можете создать Natural используя только целое число буквальным, без преобразования:

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

Однако, если вы предпочли бы остаться в области целых чисел фиксированного размера, есть решение для этого, тоже - и он был намного длиннее - Word от the module Data.Word (который также содержит, например, Word8 для 8-битных неотрицательных целых чисел). Вы должны использовать Word так же, как Natural.Однако, имейте в виду - что Word типы молча опустошения, не бросать исключение:

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 
Смежные вопросы