【问题标题】:Type-threaded heterogenous lists and defaulting(?) with type families?类型线程的异构列表和类型族的默认(?)?
【发布时间】:2012-05-27 21:04:55
【问题描述】:

我正在开发一个库,我想在其中定义一个已在此处简化为的递归类:

{-# 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

这让我可以做,例如

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

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

*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

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

【问题讨论】:

  • 您可能想考虑只使用 class Stack st 与 type Domain st a 和 type Codomain st a 之类的关联类型或类似的东西,但我没有仔细阅读以知道这是否适用你。

标签: haskell typeclass type-families


【解决方案1】:

链接问题的答案隐藏了以下非常有用的技巧:概括实例头部,并专门研究实例上下文。

instance a ~ b => StackTo a Top b where
    runStack _ = id

在选择要使用的实例时,GHC 仅检查可用的实例头(而不是上下文)并选择与当前已知的类型匹配的实例头(如果有)。在做出此选择之前,它不会专门化一个类型,即使专门化将允许一个或多个可用实例头匹配。因此,此处给出的实例与上述问题中的实例之间的区别在于,这个实例更通用:只要中间类型为Top,此实例适用,而您的实例仅适用于中间类型为Top 并且我们对其他两种类型的了解足够多,可以知道它们是平等的。

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

【讨论】:

  • 太好了,谢谢!你能澄清instance StackTo a Top a和instance a ~ b =&gt; StackTo a Top b之间的区别吗?前者更像是一个约束,而后者是一个断言平等吗? (文档似乎没有建议,所以我可能会离开)
【解决方案2】:

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

但如果您需要类型类方法,我不会干涉。

【讨论】:

  • 我实际上是在对我基于 thrist 编写的 lib 进行变体,这正是这种结构(虽然我不知道 Kleene 星,谢谢!),所以我要暴露故意的中间类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多