首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在使用MultiParamTypeClasses时,是否需要使用每个类函数中的每个类型

在使用MultiParamTypeClasses时,是否需要使用每个类函数中的每个类型
EN

Stack Overflow用户
提问于 2013-11-20 11:06:57
回答 2查看 757关注 0票数 5

当我使用MultiParamTypeClasses时,我可以创建忽略一个类型参数(例如下面的"identity“)的类函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{-# LANGUAGE MultiParamTypeClasses #-}

data Add = Add
data Mul = Mul

class Test a b where
    identity::a

instance Test Int Add where
    identity = 0

instance Test Int Mul where
    identity = 1

(这是一个精简的版本,当然在整个程序中还会有其他函数使用"b")。

示例编译,但我永远无法访问标识!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
main = do
    putStrLn (show (identity::Int))

导致“(Test b0)因使用'identity‘而产生。

有办法获取身份吗?如果不是,编译器不应该禁止我创建一个不使用所有类型参数的类函数吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-20 11:32:53

如果不是,编译器不应该禁止我创建一个不使用所有类型参数的类函数吗?

也许吧。实际上,您将永远无法使用这样的类方法。但是,由于错误总是发生在编译时,所以并不是很危险。

在某些类似情况下有效的修复(但在您的情况下):

  • 使待定类型变量在功能上依赖于其他变量之一。 {-#语言FunctionalDependencies #-}类Group_FD g p= g->p其中标识::g 这也许可以像 data Nat =1收Succ Nat实例Group_FD Nat Mult其中标识=一个实例Group_FD Int添加where标识=0 但是,显然不可能以这种方式使用相同的g元素创建多个实例。
  • 为仅依赖于此的方法定义一个只包含一个参数的分离类。然后,将该类作为另一个类的约束(“超类”),以“导入”方法: 类标识i其中标识::i类(标识i) =>测试 但是,这对您的应用程序毫无用处,因为您希望identity的行为依赖于Phantom类型变量。

为了达到你的目标,你必须以某种方式传递你想要的实例的信息。实现这一目标的一种方法是虚幻的论点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Group_PA g p where
  identity :: p -> g

instance Group_PA Int Add where
  identity _ = 0

instance Group_PA Int Mult where
  identity _ = 1

然后你就可以像这样

GHCi>标识添加::Int 0GHCi>标识Mult ::Int 1

也许更惯用的做法是将标志类型变为空。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{-# LANGUAGE EmptyDataDecls #-}
data Add
data Mult

GHCi>标识(未定义::添加) ::Int 0GHCi>标识(未定义::Mult) ::Int 1

这使我们更加清楚,幻影参数实际上没有运行时信息,只是控制编译器选择哪个实例。

无可否认,这是相当丑陋的。

right™解决方案是让新类型的包装器包含幻影信息。实际上,这样的包装器已经在标准库中了:SumProduct

票数 5
EN

Stack Overflow用户

发布于 2013-11-20 11:22:27

如果使用FlexibleInstances,则可以更改实例定义,以便可以使用标识:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

data Add = Add
data Mul = Mul

class Test a b where
    identity::a

instance Test Int b where
    identity = 0

main :: IO ()
main = do
  print $ (identity :: Int)

因为实例可以在另一个文件中定义,然后只有该文件才需要使用FlexibleInstances,所以GHC不能不允许不使用所有类型变量的类声明。

如果您想要不同b's的实例,那么您必须使用FunctionalDependencies

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20104747

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文