Haskell эквивалент assert (0) - PullRequest
       5

Haskell эквивалент assert (0)

0 голосов
/ 11 февраля 2019

Я пытаюсь выяснить, как лучше написать на Хаскелле эквивалент assert(0).Я знаю, что безопасность типов требует, чтобы целое число возвращалось из scanList, однако мне интересно, есть ли лучший способ, чем то, что я написал.Есть ли способ избежать произвольного числа 923, которое только что застряло там?

module Main (main) where

import Control.Exception (assert)

l = [
    Left "1",
    Left "1",
    Right 1,
    Right 1,
    Left "9"]

scanList :: [ Either String Int ] -> Int
scanList [    ] = 0
scanList (x:xs) = case x of
    Right i -> i + scanList xs
    Left  s ->
        if read s < 8
        then read s + scanList xs
        else assert False $ 923

main = do
    print $ scanList l

Ответы [ 2 ]

0 голосов
/ 11 февраля 2019

Более идиоматичным дизайном Haskell будет сохранение чистых функций всего .При использовании assert вы генерируете исключение, что делает функцию частичной .Это означает, что вы больше не можете доверять типу функции.В нем утверждается, что он имеет тип [Either String Int] -> Int, но при различных условиях произойдет сбой с исключением во время выполнения.

Полная функция либо останется в пределах монады Either, либо, в качестве альтернативы, может быть переведена вMaybe:

import Text.Read

scanList :: (Num a, Read a, Ord a) => [Either String a] -> Maybe a
scanList [] = Just 0
scanList (x:xs) =
  case x of
    Right i -> fmap (+ i) $ scanList xs
    Left s -> 
      case readMaybe s of
        Just i -> if i < 8 then fmap (+ i) $ scanList xs else Nothing
        Nothing -> Nothing

Вы могли бы немного упростить код, но я решил сохранить его структурно максимально приближенным к OP.

С типом, подобным [Either String a] -> Maybe aлюбой вызывающий абонент знает, что он должен обрабатывать как случаи Just, так и Nothing, не прибегая к чтению кода или документации по рассматриваемой функции.

0 голосов
/ 11 февраля 2019

Из документации assert:

Если первый аргумент имеет значение True, то результатом является второй аргумент.В противном случае возникает исключение AssertionFailed, содержащее String с исходным файлом и номером строки вызова assert.

Таким образом, вместо предоставления False в качестве первого аргумента, вы можете на самом деле проверить ifсостояние там:

scanList (x:xs) = case x of
    Right i -> i + scanList xs
    Left  s ->
        assert (read s < 8) (read s + scanList xs)
...