类型线程异构列表和缺省(?)类型族? [英] Type-threaded heterogenous lists and defaulting(?) with type families?

查看:111
本文介绍了类型线程异构列表和缺省(?)类型族?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



 我正在研究一个库,我想定义一个递归类, { - #LANGUAGE MultiParamTypeClasses 
,FlexibleInstances# - }

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

class StackTo a stc where
runStack :: st c - > (c - > a)
实例StackTo a Top a其中
runStack _ = id
实例(StackTo a st b)=> StackTo a(Snoc st b)c其中
runStack(Snoc st'cb)= runStack st'。 cb

这让我可以做到,例如

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

需要小心使用类型注释,否则... ...

pre code主要Data.Label> let f = runStack $ Snoc(Snoc Top fst)head

< interactive>:1:1:
没有用于(StackTo a0 Top b0)
的实例'runStack'
可能的修正:为(StackTo a0 Top b0)
添加一个实例声明在表达式中:runStack
在表达式中:runStack $ Snoc(Snoc Top fst)head
在'it'的等式中:it = runStack $ Snoc(Snoc Top fst)head

我认为这些问题与这个问题,但我在这里适应这个解决方案时遇到了麻烦。我可以使用类型族还是其他方法为我的递归延续堆栈提供更加用户友好的解决方案?

解决方案

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

 实例a〜b => StackTo a Top b where 
runStack _ = id

选择一个实例时,GHC仅检查可用的实例头 - 而不是上下文 - 并选择与当前已知类型相匹配的那个(如果有的话)。在进行此选择之前,它不会专门化一种类型,即使专门化可以允许一个或多个可用实例头匹配。因此,这里给出的实例和上面问题中的实例之间的区别在于,这个实例更通用:只要中间类型是 Top ,就适用这个实例,而您的应用只有当中间类型是 Top 时,我们足够了解其他两种类型才能知道它们是相同的。



你会与其他潜在的实例重叠,但这会鼓励推理引擎更强。

I'm working on a library where I want to define a recursive class that I've simplified here to:

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

This lets me do, e.g.

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

But this seems to require careful use of type annotations, otherwise...

*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

I think these are the same issues addressed in this question, but I'm having trouble adapting that solution here. Can I use type families or some other method to come up with a more user-friendly solution to my recursive continuation stack?

解决方案

The answer to the linked question hides the following quite useful trick: generalize the instance head, and specialize in the instance context.

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

When choosing an instance to use, GHC inspects available instance heads only -- not contexts -- and picks the one (if any) that matches what is currently known about a type. It will not specialize a type before making this choice, even if specializing would allow one or more of the available instance heads to match. Thus, the difference between the instance given here and the one in the question above is that this one is more general: this one applies whenever the middle type is Top, whereas yours applies only when the middle type is Top and we know enough about the two other types to know they're equal.

Yours will overlap with fewer other potential instances, but this will encourage the inference engine more strongly.

这篇关于类型线程异构列表和缺省(?)类型族?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆