【问题标题】:Convert type-level list '[a,b,c,...] to function a->b->c->将类型级列表 '[a,b,c,...] 转换为函数 a->b->c->
【发布时间】:2015-07-01 06:35:32
【问题描述】:

我有一个按类型级列表索引的数据族,其中列表中的类型对应于数据实例的参数。 我想编写根据数据实例具有不同数量和参数的函数,因此我可以将它用作系列中每个数据实例的同义词。

{-# LANGUAGE KindSignatures, DataKinds, TypeOperators, 
             TypeFamilies, FlexibleInstances, PolyKinds #-}

module Issue where


type family (->>) (l :: [*]) (y :: *) :: * where
    '[]       ->> y = y
    (x ': xs) ->> y = x -> (xs ->> y)

class CVal (f :: [*]) where
    data Val f :: *
    construct :: f ->> Val f

instance CVal '[Int, Float, Bool] where
    data Val '[Int, Float, Bool] = Val2 Int Float Bool
    construct = Val2

这编译得很好。但是当我尝试应用construct函数时:

v :: Val '[Int, Float, Bool]
v = construct 0 0 True

它会产生错误:

Couldn't match expected type `a0
                              -> a1 -> Bool -> Val '[Int, Float, Bool]'
            with actual type `f0 ->> Val f0'
The type variables `f0', `a0', `a1' are ambiguous
The function `construct' is applied to three arguments,
but its type `f0 ->> Val f0' has none
In the expression: construct 0 0 True
In an equation for `v': v = construct 0 0 True

【问题讨论】:

    标签: haskell type-families type-level-computation


    【解决方案1】:

    由于type families are not (necessarily) injective,您的代码无法进行类型检查。如果您通过在f ->> Val f 中指定f 的选择来帮助GHC,那么它会按预期工作:

    {-# LANGUAGE KindSignatures, DataKinds, TypeOperators, 
                 TypeFamilies, FlexibleInstances, PolyKinds #-}
    
    module Issue where
    
    import Data.Proxy
    
    type family (->>) (l :: [*]) (y :: *) :: * where
        '[]       ->> y = y
        (x ': xs) ->> y = x -> (xs ->> y)
    
    class CVal (f :: [*]) where
        data Val f :: *
        construct :: proxy f -> f ->> Val f
    
    instance CVal '[Int, Float, Bool] where
        data Val '[Int, Float, Bool] = Val2 Int Float Bool deriving Show
        construct _ = Val2
    
    v :: Val '[Int, Float, Bool]
    v = construct (Proxy :: Proxy '[Int, Float, Bool]) 0 0 True
    

    关键是将Proxy :: Proxy '[Int, Float, Bool] 参数传递给construct,从而修正f 的选择。那是因为没有什么能阻止你拥有f1f2 这样的f1 ->> Val f1 ~ f2 ->> Val f2 类型。

    别担心,this shortcoming of the language is being looked at

    【讨论】:

    • "没有什么能阻止你拥有f1f2 这样的f1 ->> Val f1 ~ f2 ->> Val f2 类型。"实际上,有:(->>) 是封闭的,Val 是一个数据族(不是类型族),因此是单射的。不幸的是,GHC 在任何推理过程中都没有利用类型族的封闭性(还没有?)。
    猜你喜欢
    • 2020-07-15
    • 2011-05-30
    • 2018-09-14
    • 2020-07-08
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    相关资源
    最近更新 更多