Haskell 从类型类解析中获取派生

Haskell 从类型类解析中获取派生,haskell,constraints,typeclass,Haskell,Constraints,Typeclass,我们可以使用Dict得到[Int]有一个Show实例的值级证明 {-# LANGUAGE ConstraintKinds, GADTs #-} data Dict (p :: Constraint) where Dict :: p => Dict p 及 有没有一种方法可以得到一个值级的派生,即整个证明树 derivation = Apply@Int(Lam a.(Show a) :=> Show [a])) (Apply(() :=> Show Int)()) 没有

我们可以使用
Dict
得到
[Int]
有一个Show实例的值级证明

{-# LANGUAGE ConstraintKinds, GADTs #-}
data Dict (p :: Constraint) where
  Dict :: p => Dict p

有没有一种方法可以得到一个值级的派生,即整个证明树

derivation = Apply@Int(Lam a.(Show a) :=> Show [a])) (Apply(() :=> Show Int)()) 

没有一种方法可以将任意约束的派生作为Haskell值

我能想到的最接近的事情,如果你想检查推导是否是你所认为的,就是看去糖化器的输出

ghc -ddump-ds -ddump-to-file A.hs
相关部分如下所示:

-- RHS size: {terms: 2, types: 1, coercions: 0, joins: 0/0}
irred :: Show [Int]
[LclId]
irred = GHC.Show.$fShow[] @ Int GHC.Show.$fShowInt

-- RHS size: {terms: 2, types: 3, coercions: 0, joins: 0/0}
proof :: Dict (Show [Int])
[LclIdX]
proof = Cns.Dict @ (Show [Int]) irred
另一种方法是编写定制的类型类,用类型或值来反映派生,但这当然不适用于先前存在的类型类

{-# LANGUAGE AllowAmbiguousTypes, ConstraintKinds, GADTs, DataKinds,
   FlexibleInstances, KindSignatures, MultiParamTypeClasses, RankNTypes,
   ScopedTypeVariables, TypeApplications, TypeOperators,
   UndecidableInstances #-}

import Data.Typeable
import Data.Kind

data (c :: [Type]) :=> (d :: Type -> Constraint)

class MyShow a d where
  myshow :: a -> String

instance (d ~ ('[] :=> MyShow Int)) => MyShow Int d where

instance (MyShow a da, d ~ ('[da] :=> MyShow [a])) => MyShow [a] d where

myshowInstance :: forall a d. (Typeable d, MyShow a d) => TypeRep
myshowInstance = typeRep @_ @d Proxy

main = print (myshowInstance @[Int])
可以使输出看起来更好,例如,通过一个具有适当渲染方法的单例,而不是
TypeRep
,但我希望您了解主要想法

:=> (': * (:=> ('[] *) (MyShow Int)) ('[] *)) (MyShow [Int])

这可能是你想要的,或者至少足以给你一个大致的想法。我想不出一种让GHC自动提供的方法,但是您可以使用
constraints
包手动构建证明约束的包含链

无论出于何种原因,都没有
实例():=>Show Int
,因此我使用了
Char
。这可能是一个疏忽,我打开了一个pull请求来添加缺少的实例

{-# LANGUAGE ConstraintKinds #-}

import Data.Constraints

derivation :: () :- Show [Char]
derivation = trans showList showChar
    where showList :: Show a :- Show [a]
          showList = ins

          showChar :: () :- Show Char
          showChar = ins
不幸的是,打印此值不会显示内部派生,只显示
“Sub Dict”


一个有趣的练习可能是尝试使用
Data.Constraint.Forall
使用显式
TypeApplications
编写
派生
。你还需要几个额外的步骤来证明
Show a:-Forall Show
ForallF Show[]:-Show[a]

这确实是一个有趣的练习!
{-# LANGUAGE ConstraintKinds #-}

import Data.Constraints

derivation :: () :- Show [Char]
derivation = trans showList showChar
    where showList :: Show a :- Show [a]
          showList = ins

          showChar :: () :- Show Char
          showChar = ins