StackOverflow!
For reasons that would like to remain between me and God, I'm currently playing around with promoting runtime naturals to the type level. I've been following this approach with GHC.TypeLits, which has worked out fine so far.
However, in one instance, I have an additional constraint of 1 <= n
, i.e. my promoted natural not to be just any natural, but at least 1. This is also from GHC.TypeLits And I am unsure if/how it is possible to extract and make that information known.
Here's a minimal non-working example:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
import Data.Maybe
import Data.Proxy
import GHC.TypeLits
import Numeric.Natural
data AnyNat (n :: Nat) where
AN :: AnyNat n
data AtLeast1Nat (n :: Nat) where
AL1N :: AtLeast1Nat n
promote0 :: Natural -> AnyNat n
promote0 k = case sn of
SomeNat (_ :: Proxy p) -> AN
where
sn = (fromJust . someNatVal . toInteger) k
promote1 :: (KnownNat n, 1 <= n) => Natural -> AtLeast1Nat n
promote1 k = case sn of
SomeNat (_ :: Proxy p) -> AL1N
where
sn = (fromJust . someNatVal . toInteger) k
main :: IO ()
main = do nat_in <- getLine
let nat = read nat_in :: Natural
let p0 = promote0 nat
let p1 = promote1 nat
putStrLn "Last statement must be an expression"
This produces this error (full error here, but this is the relevant part):
* Couldn't match type `1 <=? n0' with 'True
arising from a use of `promote1'
The type variable `n0' is ambiguous
Honestly, this isn't too surprising and I (think I) do understand why this happens. The Natural
that we give in could be any of them, so why would we be able to derive that 1 <= n
? That's why it works fine for promote0
and not promote1
.
My question is hence, is there any way to also check (and propagate to type-level) this information so I can use it as intended, or am I using the wrong approach here?