I tried to write a couple of functions that parse numbers properly, with all the checking (of signature `String -> Maybe a` for some collection of `a`). I have written function that parses unbounded `Integer` (`maybeReadInteger`), and then I wanted to write polymorphic function that parses all bounded integer types: just wrap `maybeReadInteger` in some range checking. `maybeReadNum` is attempt to write such function, but it doesn't typecheck. Can it be written like this? What language extensions (if any) I have to turn on?

``splitIntoSignAndDigits str = case str of'-':rest -> (-1, rest)'+':rest -> ( 1, rest)_ -> ( 1, str )maybeReadUnsignedInteger [] = NothingmaybeReadUnsignedInteger [email protected](x:xs) = go 0 strwhere go n str = case str of[] -> Just n(x:xs) | '0' <= x && x <= '9' -> go (10 * n + digit) xs| otherwise -> Nothingwhere digit = toInteger (ord x - ord '0')maybeReadInteger str = fmap (sign*) (maybeReadUnsignedInteger str')where (sign, str') = splitIntoSignAndDigits strmaybeReadNum :: (Integral a, Bounded a) => String -> Maybe amaybeReadNum = fmap fromInteger .mfilter (\n -> n >= toInteger (minBound :: a) &&n <= toInteger (maxBound :: a)) .maybeReadInteger``

Monomorphic function like this:

``maybeReadInt :: String -> Maybe IntmaybeReadInt = fmap fromInteger .mfilter (\n -> n >= toInteger (minBound :: Int) &&n <= toInteger (maxBound :: Int)) .maybeReadInteger``

works OK.

The problem is that the `a` in your signature for `minBound` is not the same as the `a` in the signature of `maybeReadNum`. You can fix this by turning on `ScopedTypeVariables`:

``````{-# LANGUAGE ScopedTypeVariables #-}

-- We need to use forall explicitly, otherwise ScopedTypeVariables doesn't take effect.
maybeReadNum :: forall a. (Integral a, Bounded a) => String -> Maybe a
mfilter (\n -> n >= toInteger (minBound :: a) &&
n <= toInteger (maxBound :: a)) .
``````

An alternative is to use a helper like `asTypeOf`:

``````maybeReadNum :: (Integral a, Bounded a) => String -> Maybe a
maybeReadNum = fmap ((`asTypeOf` minBound') . fromInteger) .
mfilter (\n -> n >= toInteger minBound' &&
n <= toInteger maxBound') .
where minBound' = minBound
maxBound' = maxBound `asTypeOf` minBound'
``````

`asTypeOf` is defined as follows:

``````asTypeOf :: a -> a -> a
asTypeOf = const
``````

It is just `const` with a more restricted type siganture. This can be used to assert the the the types of two expressions should be the same, which helps the compiler to infer the right types.

In the above code, `asTypeOf` is used to assert that `minBound'` should have the same type as the result of fromInteger, which in turn must equal to the `a` from the signature of `maybeReadNum`. From this, the compiler infers that `minBound'` is of type `a`. Then `maxBound'` should also have the same type, so it also gets the type `a`. This is a bit more difficult, and it's probably easier and better to just use `ScopedTypeVariables`, it might however be a method to retain portable across compilers (in case you aren't already using some extensions).

Top