Haskell简化依赖类型函数签名

eqqqjvef  于 2023-02-23  发布在  其他
关注(0)|答案(1)|浏览(170)

这是一个依赖类型haskell函数dfunc的例子,它的类型取决于参数值:0Map到Int的值,1Map到Integer的值,等等,如下面类型族中定义的。
所以我有一个函数,带有签名,但是我想去掉这个奇怪的int编码,然后用类型签名,实现一个函数,我知道,类型对于这个来说太通用了,但是我尝试用,没有类型签名的函数,来欺骗,让haskell来做类型推断,并得到错误,据我所知,因为ff实现在类型签名中无法表达。
我可以在这里使用一些“魔法”来删除GADTInt a -> Dt a并将其替换为Int -> ?

{-# LANGUAGE DataKinds      #-}
{-# LANGUAGE GADTs          #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
module Main where

data Nat :: * where
    Z :: Nat
    S :: Nat -> Nat

data GADTInt a where
    GADTZero :: GADTInt Z
    GADTOne :: GADTInt (S Z)
    GADTTwo :: GADTInt (S (S Z))   
    GADTThree :: GADTInt (S (S (S Z)))   

type family Dt a where
    Dt 'Z = Int
    Dt ('S 'Z) = Integer
    Dt ('S ('S 'Z)) = Float
    Dt ('S ('S ('S 'Z))) = String

class NTI a where
    toi :: a -> Int

instance NTI (GADTInt a) where
    toi GADTZero = 0 
    toi GADTOne = 1 
    toi GADTTwo = 2
    toi GADTThree = 3

dfunc :: GADTInt a -> Dt a
dfunc GADTZero = 1
dfunc GADTOne = 1000000000000000000000000000000
dfunc GADTTwo = 3.14
dfunc GADTThree = "Hi"

ff i 
     | toi GADTZero == i = dfunc GADTZero     
     | toi GADTOne == i = dfunc GADTOne
     | toi GADTTwo == i = dfunc GADTTwo     
     | toi GADTThree == i = dfunc GADTThree
     | otherwise = undefined
9gm1akwq

9gm1akwq1#

使用Dt a的唯一方法是知道a是什么。因为类型被擦除,所以你需要它的运行时表示,例如使用GADTInt单例。你可以把它们打包成一个存在类型:

data SomeDt where
  SomeDt :: GADTInt a -> Dt a -> SomeDt

用另一个存在类型 Package 单例也很有用:

data SomeGADTInt where
  SomeGADTInt :: GADTInt a -> SomeGADTInt

以便定义"非相关"标记:

toTag :: Int -> SomeGADTInt
toTag 0 = SomeGADTInt GADTZero
toTag 1 = SomeGADTInt GADTOne
toTag 2 = SomeGADTInt GADTTwo
toTag 3 = SomeGADTInt GADTThree

包裹dfunc

someDFunc :: SomeGADTInt -> SomeDt
someDFunc (SomeGADTInt i) = SomeDt i (dfunc i)

组成:

ff :: Int -> SomeDt
ff = someDFunc . toTag

相关问题