2013-01-04 161 views
5

我正在研究一个包含monoid的applicative函数来“查看”执行。然而,有时候我根本不关心这个部分,所以幺半群的选择是不相关的,因为它永远不会被消耗。我已经简化我有什么到:使用约束类型和类型族具有“受限制”的约束

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE ConstraintKinds #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies #-} 

import GHC.Exts 

class Render a b where render :: a -> b 
instance Render a() where render = const() 

class Merge a where 
    type Renderer a b :: Constraint 
    merge :: Renderer a b => a -> b 

data Foo = Foo Bool 

instance Merge Foo where 
    type (Renderer Foo) m = (Render Bool m) 
    merge (Foo b) = render b 

Render用于各种a转换且为单一bMerge是我的实际仿函数的一个很大的简化,但重点是它包含一个类型族/约束,我的目的是明确指定什么RenderMerge需要。现在

,我可能要“跑”的Merge,但丢弃的观点,这是类似于这样的:

runFoo :: Merge a => a -> Int 
runFoo x = case merge x of() -> 5 

但因为这将失败:

无法推断(Renderer a())从使用merge

我选择()我的幺因为˚F产生或者a,我们有一个Render a()的实例。所以如果有一种方法可以说Merge a只是意味着收集Render约束,那么这将工作正常。当然,Merge a比这更一般 - 它可以添加任意约束,这就解释了编译错误。

有没有办法实现我想要的没有更改runFoo的签名?

+0

是否'Renderer'总是正好包括一个'Render'? – 2013-01-04 13:55:21

+0

@Tinctorius - 不,通常取决于'Foo'字段中不同类型的数量 – ocharles

+0

'Merge'没有'b'作为参数吗? –

回答

6

,如果你有很多这种情况下,这可能不是规模,但这个工程:

class Renderer a() => Merge a where 
    ... 
+0

我没有考虑过。我可以阅读这个约束,因为''合并'应该至少支持用'()'monoid'进行渲染。但是,这会产生'UndecidableInstances'。 – ocharles

+0

“UndecidableInstances不是一个危险的标志,它永远不会导致类型检查程序接受出错的程序。使用该标志的唯一不良后果就是类型检查器可能告诉我们,由于上下文堆栈深度限制,它无法确定我们的程序是否打好了类型。“ http://okmij.org/ftp/Haskell/TypeClass.html#undecidable-inst-defense –

+0

我知道,我已经在其他3个地方使用它了)但理想情况下,我喜欢找到不需要它的解决方案,即使纯粹由于学术原因。我可能会接受这个答案,只是让这个问题开放一段时间。这确实是一种享受! – ocharles