haskell - 高级类型类的量化约束
问题描述
假设我想写两个 Typeclass。标题:
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Complex
第一个类型类 ExClass 是这样定义的:
class (forall a. (Monoid (t a))) => ExClass t where
exFunc :: [t (Complex a)] -> t (Complex a)
exFunc = mconcat -- the actual function is more complicated
exFunc2 :: (RealFloat a) => t (Complex a) -> a
我将它定义为更高种类的类型类,因为它的一个函数的输出类型取决于其嵌套值的类型a
。我也希望有一个默认实现,但它涉及到MonoidexFunc
的假设。t a
现在我想为以下类型编写一个实例:
newtype ExType a = ExType a
ExType a
仅当Num a
为真时才为 Monoid:
instance (Num a) => Semigroup (ExType a) where
ExType a <> ExType b = ExType (a * b)
instance (Num a) => Monoid (ExType a) where
mempty = ExType 1
现在我继续为 定义类型类实例ExClass
,指定 的约束Num a
:
instance (forall a. Num a) => ExClass ExType where
exFunc2 (ExType a) = magnitude a
上面的代码将毫无问题地编译。但是,如果我尝试像这样使用已实现的功能:
x = ExType 2 :: ExType (Complex Double)
func = exFunc2 x
我收到以下投诉:
• No instance for (Num a) arising from a use of ‘exFunc2’
Possible fix: add (Num a) to the context of a quantified context
• In the expression: exFunc2 x
In an equation for ‘func’: func = exFunc2 x
当我使用不同的实例声明时也会发生这种情况:
instance (forall a. Monoid(ExType a)) => ExClass ExType where
exFunc2 (ExType a) = magnitude a
有没有办法让这个类型类工作?还是我根本不应该像这样构建我的程序?
解决方案
丹尼尔瓦格纳已经在他的回答中解释了当前定义的问题。
似乎您想要的意思是“一类与应用于其元素ExClass
的另一个类具有特殊关系的容器类型,并且当它们的元素满足时,容器本身就是幺半群”。c
c
例如:ExType
与 有特殊关系Num
。当满足的元素,a
就变成了。ExType
Num
ExType a
Monoid
(这已经在ExType
sMonoid
实例中得到确认,但您似乎想用更高级别的抽象来表达它;为那些以类似方式成为幺半群的容器提供一个类。)
在 Haskell 中,有多种可能的方式来表达两种类型之间的关系——或者类型和Constraint
. 让我们使用MultiParameterTypeClasses
:
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ConstraintKinds #-}
import Data.Kind (Type, Constraint)
-- This kind signature is not strictly required, but makes things clearer
type ExClass :: (Type -> Constraint) -> (Type -> Type) -> Constraint
class (forall a . c a => Monoid (t a)) => ExClass c t | t -> c where
exFunc :: c a => [t a] -> t a
exFunc = mconcat
请注意,ExClass
现在有两个参数,并且f
容器的类型(通过函数依赖)确定了 for 元素所需的约束c
为a 。不同的s可能会有所不同!f
f
Monoid
c
f
的Semigroup
和Monoid
实例ExType
不变。现在的ExClass
实例ExType
是:
instance ExClass Num ExType where
exFunc = mconcat
让它发挥作用:
main :: IO ()
main = print $ exFunc [ExType (1::Int), ExType 2]
(我省略了Complex
数据类型,这可能会在定义中引发另一个问题。)
推荐阅读
- java - 使用 Jackson 转换为 JSON 时处理空 XML 节点
- r - 如何修复 tidygraph 中的“不应直接调用函数”错误?
- sql - SQL Else If 语句从另一列的数值返回文本值 - 不起作用
- php - 服务器拒绝从 https 重定向到 https
- c# - Math.Net FFT Bin 宽度
- javascript - 如何在浏览器中运行隔离的 Node.js 环境?
- codeigniter-3 - 前端无法保存在函数插入 $data
- python - 如何将测试数据帧放在预测数据帧的同一数据帧中
- javascript - 单击另一个框中的选项时更改选择框中的选项
- mysql - 如何创建循环以将完成的文件发送到不同的目录(已关闭)