Haskell 将约束类型和类型族与';有限公司';约束条件

Haskell 将约束类型和类型族与';有限公司';约束条件,haskell,type-families,constraint-kinds,Haskell,Type Families,Constraint Kinds,我正在处理一个应用程序函子,它包含一个用于“查看”执行的幺半群。然而,有时我根本不关心这一部分,所以选择幺半群是不相关的,因为它永远不会被消费。我已将我的内容简化为: {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} import GHC.Exts class Rende

我正在处理一个应用程序函子,它包含一个用于“查看”执行的幺半群。然而,有时我根本不关心这一部分,所以选择幺半群是不相关的,因为它永远不会被消费。我已将我的内容简化为:

{-# 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
s转换为单个
b
Merge
是我的实际函子的一个大简化,但关键是它包含一个类型族/约束,我的意图是精确地指定
Render
ers
Merge
需要什么

现在,我可能想“运行”合并,但放弃视图,类似于:

runFoo :: Merge a => a -> Int
runFoo x = case merge x of () -> 5
但这将失败,因为:

无法推断使用
合并产生的
(渲染器a())

我选择
()
作为我的幺半群,因为对于所有
a
,我们都有一个
呈现a()
的实例。因此,如果有一种方法可以说
Merge a
仅仅意味着一个集合
Render
约束,那么这就可以了。当然,
Merge a
比这更一般-它可以添加任意约束,这就解释了编译错误


在不更改
runFoo
的签名的情况下,是否仍然可以实现我想要的功能?

如果您有很多这样的情况,这可能无法扩展,但这是有效的:

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

Renderer
是否始终只包含一个
Render
?@Tinctorius-否,通常取决于
Foo
字段中不同类型的数量
Merge
是否有理由不将
b
作为参数?@C.a.McCann-没有理由,但我也看不出有什么理由。如果这会有帮助的话,我可以把它带进来,但我不能马上看出它会有什么帮助。一般来说,将某个东西作为类参数会给你提供更多表达复杂约束的选项。不过,我没想到会有什么特别的想法。我可以将该约束理解为“
Merge
s应该至少支持使用
()
monoid”进行渲染”。但是,这确实会导致不可判定的实例。“不可判定的实例不是危险的标志。它永远不会导致类型检查器接受“出错”的程序。使用该标志的唯一不良后果是类型检查器可能会告诉我们,鉴于上下文堆栈的深度限制,它无法确定程序是否类型正确。“我知道,我已经在其他三个地方使用过它;)但理想情况下,我喜欢找到不需要的解决方案,即使纯粹出于学术原因。我可能会接受这个答案,只是让场地开放一段时间。这真是一种享受!