Chcę przeczytać stosunek ze sznurka, ale nie chcę, aby mój program był awarią, gdy mianownik ma zero. Jak mogę wykryć zerowy mianownik i uniknąć błędu? Po prostu użycie readMaybe nie działa:

Prelude Text.Read> readMaybe "1 % 0" :: Maybe Rational
Just *** Exception: Ratio has zero denominator

Stworzyłem to daleko od idealnego rozwiązania:

readMaybeRational :: String -> Maybe Rational
readMaybeRational s =
  case ((readMaybe $ drop 1 $ dropWhile (/='%') s) :: Maybe Int)
    of Just 0 -> Nothing
       _ -> readMaybe s

Ale nie wiem, jak ładnie poradzić sobie z zagnieżdżonym współczynnikiem:

"Just (1 % 0)"

Gdybym mógł zastąpić instancję czytania wskaźnika, mogłem uzyskać ReadMaybe, aby nic nie zwrócić, gdy mianownik ma zero:

instance (Integral a, Read a) => Read (Ratio a) where
  readPrec =
    parens
    ( prec ratioPrec
      ( do x <- step readPrec
           expectP (L.Symbol "%")
           y <- step readPrec
           -- is y 0? If so, do something here
           return (x % y)
      )
    )

Ale jestem pewien, że nie mogę tego zrobić.

11
bwroga 26 lipiec 2020, 00:43

1 odpowiedź

Najlepsza odpowiedź

Myślę, że twoje najlepsze rozwiązanie jest newtype {} Ratio, podobnie:

import Control.Monad
import GHC.Read
import GHC.Real
import qualified Text.Read.Lex as L
import Text.ParserCombinators.ReadPrec

newtype SaneReadRatio a = SaneReadRatio (Ratio a)
type SaneReadRational = SaneReadRatio Integer

instance (Integral a, Read a) => Read (SaneReadRatio a) where
  readPrec =
    parens
    ( prec ratioPrec
      ( do x <- step readPrec
           expectP (L.Symbol "%")
           y <- step readPrec
           guard (y /= 0)
           return (SaneReadRatio (x % y))
      )
    )

  readListPrec = readListPrecDefault
  readList     = readListDefault

Użyj go, czytając w danych za pomocą {x1}} zamiast Rational, a następnie za pomocą coerce z Data.Coerce w wyniku tego, co zmieni ją z powrotem do podstawowego {x4 }} Bez względu na to, jak głęboko zakopuje się wewnątrz twojego typu.

4
Joseph Sible-Reinstate Monica 26 lipiec 2020, 22:15