TypeLits or Singletons: promoting `Integer` in` KnownNat` (`Nat`) at run time

I found two ways to push Integer to Nat (or KnownNat, I haven't got distintion yet) at runtime, either using TypeLits and Proxy (Data.Proxy and GHC.TypeLits), or Singletons (Data.Singletons). In the code below, you can see how each of the two approaches is used:

{-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE NoImplicitPrelude #-} module Main where import Prelude hiding (replicate) import Data.Proxy (Proxy(Proxy)) import Data.Monoid ((<>)) import Data.Singletons (SomeSing(..), toSing) import GHC.TypeLits import Data.Singletons.TypeLits import Data.Vector.Sized (Vector, replicate) main :: IO () main = playingWithTypes 8 playingWithTypes :: Integer -> IO () playingWithTypes nn = do case someNatVal nn of Just (SomeNat (proxy :: Proxy n)) -> do -- let (num :: Integer) = natVal proxy -- putStrLn $ "Some num: " <> show num putStrLn $ "Some vector: " <> show (replicate 5 :: Vector n Int) Nothing -> putStrLn "There no number, the integer was not a natural number" case (toSing nn :: SomeSing Nat) of SomeSing (SNat :: Sing n) -> do -- let (num :: Integer) = natVal (Proxy :: Proxy n) -- putStrLn $ "Some num: " <> show num putStrLn $ "Some vector: " <> show (replicate 5 :: Vector n Int) 

The documentation for TypeLits indicates that it should not be used by developers, but Singletons do not fix a case in which this Integer is not a natural number (i.e., playingWithTypes 8 without errors, but playingWithTypes (-2) fails when we try create Singleton from an unnatural number).

So what is the “standard” way to push Integer to Nat ? Or what's the best approach to promotion using TypeLits and Proxy or Singletons?

+5
source share
1 answer

Nat (or KnownNat , I don't get distintion yet)

Nat is the type of natural numbers of the type. He has no residents at the timeline level. The idea is that the GHC promotes any natural number at the level level and gives it the form Nat .

KnownNat is a restriction on something like Nat , the implementation of which shows how to transform a thing of the form Nat into the terminological level of Integer . GHC automatically creates KnownNat instances for all type types of type type Nat 1 .

However, if every n :: Nat (reading type n type Nat ) has an instance of KnownNat on it, 1 you still need to write a restriction.

I found two ways to promote Integer in Nat

You really? At the end of Nat day today, the GHC is just magical. singletons enters into the same magic. Under the hood uses someNatVal .

So what is the “standard” way to push Integer to Nat ? Or what is the best approach to promotion using GHC.TypeLits and Proxy , or singleton?

There is no standard way. My trick: use singletons when you can afford its dependency and GHC.TypeLits otherwise. The advantage of singletons is that a class of type SingI allows SingI to conveniently conduct analysis based on induction, while relying on a special type of Nat GHC.


1 As noted in the comments, not every resident of type Nat has an instance of KnownNat . For example, Any Nat :: Nat , where Any is one of the GHC.Exts . Only residents 0 , 1 , 2 , ... have KnownNat instances.

+7
source

Source: https://habr.com/ru/post/1272631/


All Articles