类型线程异构列表和类型系列的默认(?)?

jbe*_*man 3 haskell typeclass type-families

我正在创建一个库,我想在这里定义一个递归类,我在这里简化为:

{-# LANGUAGE MultiParamTypeClasses 
           , FlexibleInstances #-}

data Snoc st b c = Snoc (st b) (c -> b) 
data Top a = Top

class StackTo a st c  where
     runStack :: st c -> (c -> a)
instance StackTo a Top a where
     runStack _ = id
instance (StackTo a st b) => StackTo a (Snoc st b) c where
     runStack (Snoc st' cb) = runStack st' . cb
Run Code Online (Sandbox Code Playgroud)

这让我这样做,例如

*Main Data.Label> let f = runStack $ Snoc (Snoc Top fst) head :: [(a,x)] -> a
*Main Data.Label> f [('a',undefined)] 
'a'
Run Code Online (Sandbox Code Playgroud)

但这似乎需要小心使用类型注释,否则......

*Main Data.Label> let f = runStack $ Snoc (Snoc Top fst) head

<interactive>:1:1:
    No instance for (StackTo a0 Top b0)
      arising from a use of `runStack'
    Possible fix: add an instance declaration for (StackTo a0 Top b0)
    In the expression: runStack
    In the expression: runStack $ Snoc (Snoc Top fst) head
    In an equation for `it': it = runStack $ Snoc (Snoc Top fst) head
Run Code Online (Sandbox Code Playgroud)

我认为这些问题与此问题相同,但我在此处无法适应该解决方案.我可以使用类型族或其他方法为我的递归延续堆栈提供更加用户友好的解决方案吗?

Dan*_*ner 7

链接问题的答案隐藏了以下非常有用的技巧:概括实例头,并专注于实例上下文.

instance a ~ b => StackTo a Top b where
    runStack _ = id
Run Code Online (Sandbox Code Playgroud)

在选择要使用的实例时,GHC仅检查可用的实例头 - 而不是上下文 - 并选择与当前已知类型相匹配的实例头(如果有的话).在做出此选择之前,它不会专门化类型,即使专门化允许一个或多个可用实例头匹配.因此,这里给出的实例和一个在上面的问题之间的区别是,这个人是比较一般:这一个适用于任何中间类型Top,而你只适用于中等类型是Top 我们不够了解其他两个知道他们是平等的类型.

您将与更少的其他潜在实例重叠,但这将更强烈地鼓励推理引擎.


pig*_*ker 6

Kleene明星 GADT不会做这项工作有什么特别的原因吗?

data Star r a b where
  Nil   :: Star r a a
  Cons  :: r a b -> Star r b c -> Star r a c

compose :: Star (->) a b -> a -> b
compose Nil          = id
compose (Cons f fs)  = compose fs . f
Run Code Online (Sandbox Code Playgroud)

但是如果你需要类型类方法,我不会干涉.