如何编写函数将泛型类型转换为Tag形式以便与DSum一起使用?

时间:2016-11-20 23:45:03

标签: haskell generic-programming

如何实现此Code功能?我已经设法得到基本案例进行编译,但我不知道如何在递归调用中携带所有类型信息。在尝试递归之前,是否必须从类型中删除{-# LANGUAGE GADTs #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module Foo where import Data.Dependent.Sum import Data.GADT.Compare import Data.Proxy import Generics.SOP import qualified GHC.Generics as GHC type GTag t = GTag_ (Code t) newtype GTag_ t (as :: [*]) = GTag (NS ((:~:) as) t) instance GEq (GTag_ t) where geq (GTag (Z Refl)) (GTag (Z Refl)) = Just Refl geq (GTag (S x)) (GTag (S y)) = GTag x `geq` GTag y geq _ _ = Nothing toDSum :: forall t . Generic t => t -> DSum (GTag t) (NP I) toDSum = foo . unSOP . from where foo :: () => NS (NP I) (Code t) -> DSum (GTag t) (NP I) foo = bar (Proxy :: Proxy t) bar :: forall t1 . () => Proxy t1 -> NS (NP I) (Code t1) -> DSum (GTag t1) (NP I) bar _ (Z x) = GTag (Z Refl) :=> x bar _ (S x) = undefined

(这是How can I write this GEq instance?

的后续内容
{{1}}

2 个答案:

答案 0 :(得分:3)

此代码的一个版本在我的other答案中,但类型略有不同,这实际上简化了代码。

正如您在instance GEq (GTag_ t)看到的那样,当您想要在NSNP上编写归纳函数时,您需要保持索引参数化 - 您会看到这种一般模式“依赖”编程(真正依赖编程和在Haskell中伪装)。

这正是bar

的问题
forall t1 . () => Proxy t1 -> NS (NP I) (Code t1) -> DSum (GTag t1) (NP I)
                                        ^^^^^^^^^

这样的函数无法递归 - 只是因为如果S rep :: NS (NP I) (Code t1),那么rep :: NS (NP I) (Code t2) t2对于某些toTagValG来说并不一定如此(事实上,情况从未如此) {1}} - 即使这个事实 为真,你也很难说服编译器。

您必须在索引中使用此功能(重命名为type GTagVal_ t = DSum (GTag_ t) (NP I) type GTagVal t = DSum (GTag t) (NP I) toTagValG :: NS f xss -> DSum (GTag_ xss) f toTagValG (Z rep) = GTag (Z Refl) :=> rep toTagValG (S rep) = case toTagValG rep of GTag tg :=> args -> GTag (S tg) :=> args )参数:

xss

当您使用Code tto时,fromfrom :: a -> Rep a实例化,Rep a = SOP I (Code a)toTagVal :: Generic a => a -> GTagVal a toTagVal = toTagValG . unSOP . from

fromTagVal :: Generic a => GTagVal a -> a 
fromTagVal = to . SOP . (\(GTag tg :=> args) -> hmap (\Refl -> args) tg) 

注意推断此类型(如果关闭MonomorphismRestriction)

另一个方向更简单:

fromTagValG :: DSum (GTag_ xss) f -> NS f xss 
fromTagValG (GTag (Z Refl) :=> rep) = Z rep 
fromTagValG (GTag (S tg) :=> args) = S $ fromTagValG $ GTag tg :=> args 

虽然您也可以使用感应在lambda中编写函数:

toTagValG

请注意,您可以为此函数指定一个非常通用的类型,NP I - 实际上,它根本没有提到NS f xss。你也应该能够使自己相信这些函数是彼此反转的,因此见证了DSum (GTag_ xss) ffindContact(searchKey){ if(searchKey.target.value == "" || searchKey.target.value == undefined || searchKey.target.value == null){ this.contactSelected = false; } else{ this.contactSelected = true; } let options = { multiple: true, hasPhoneNumber: true, filter: searchKey.target.value } let cantactFields = ['displayName', 'phoneNumbers']; Contacts.find(cantactFields, options).then(res => { this.contactResults = res; }, (er) => { console.log(er); }) } 之间的同构。

答案 1 :(得分:3)

尽管已经回答了这个问题,但无论如何我都会添加自己的,因为我花了几个小时来解决它。

短而甜蜜

toDSum :: Generic t => t -> DSum (GTag t) (NP I)
toDSum = foo (\f b -> GTag f :=> b) . unSOP . from
  where
    foo :: (forall a . (NS ((:~:) a) xs) -> NP I a -> r)
        -> NS (NP I) xs
        -> r
    foo k (Z x) =     (k . Z) Refl x
    foo k (S w) = foo (k . S)      w