これは、Haskell の Data.Reflection に関するタイプの質問です。リフレクションを使用すると、Int を取得して型に変換できます。
以下の関数 f と g は、合理的な方法で最善を尽くしたものです。
たとえば、次のようにして 41 を法とする数値を追加できます。
import Data.Reflection
import Data.Proxy
newtype Zq q i = Zq i deriving (Eq)
instance (Reifies q i, Integral i) => Num (Zq q i) where
(...)
zqToIntegral :: (Reifies q i, Integral i) => Zq q i -> i
(...)
f :: forall i . (Integral i) => i -> (forall q . Reifies q i => Zq q i) -> i
f modulus k =
reify modulus (\ (_::Proxy t) -> zqToIntegral (k :: Zq t i)
それで
>>:t (f 41 (31+15))
(f 41 (31+15)) :: Integral i => i
ただし、次のような関数を書きたいと思います。
g :: forall i . (Integral i) => i -> (forall q . Reifies q i => Zq q i) -> Zq q i
g modulus k =
reifyIntegral modulus (\ (_::Proxy t) -> (k :: Zq t i)
そして取得したい:
>>:t (g 41 (31+15))
(g 41 (31+15)) :: <some type info> => Zq q i
違いは、具体化された int を使用する型を返せるようにしたいということです。上記の定義に関する少なくとも 1 つの問題は、ランク 2 の型 q が戻り値の型から見えないことです。
Data.Reflection の reify の署名は次のとおりです。
reify :: a -> (forall s. Reifies s a => Proxy s -> r) -> r
私たちが知る限り、これにはランク 2 の型が必要であり、この型を関数の戻り値の型に公開する方法が (実際に可能であれば) わかりません。