问题
The only way I know to construct a Nat
is to use -XDataKinds
with promoted integers, i.e., type MyInt = 10 :: Nat
.
Instead, I'd like to have a function
foo :: Integer -> Integer
that I can index with a reflected Nat
, and then reify the result. To demonstrate what I mean, assume some function mkNat :: Integer -> Q Type
. I want to write
type Z = $(mkNat $ foo $ natVal (Proxy::Proxy 10))
(In my example, foo
is fast enough that it can be computed at compile time without prohibitive overhead.) Having this capability saves me the multi-step process of running foo
in a separate GHCi session, then copying the decimal representation of the result into a source file, and then compiling the code I really wanted.
Of course the only missing component is mkNat
. If I write my own custom data type, the equivalent of mkNat
is easy to write. But I'd really like to use the built-in TypeLits. Is there some TemplateHaskell (or singletons, or some other magic) that would allow me to reify an arbitrary Integer
expression to a Nat
?
回答1:
Yes!
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Data.Proxy
import GHC.TypeLits
import Splices
type Z = $(mkNat $ natVal (Proxy :: Proxy 10))
And then:
module Splices where
import Language.Haskell.TH
mkNat :: Integer -> Q Type
mkNat = return . LitT . NumTyLit
来源:https://stackoverflow.com/questions/36062614/typelit-from-generic-integer-expression