Haskell 作为类型类实例的函数?
Haskell 作为类型类实例的函数?,haskell,typeclass,Haskell,Typeclass,{-#语言LambdaCase} 我有一系列函数,它们以各种方式编码失败。例如: f::A->Bool在失败时返回False g::B->Maybe B'失败时返回Nothing h::C->任一错误C'在失败时返回Left… 我希望以与Maybemonad相同的方式链接这些操作,因此链接函数需要在继续下一个函数之前知道每个函数是否失败。为此,我编写了以下课程: class Fail a where isFail :: a -> Bool instance Fail () wher
{-#语言LambdaCase}
我有一系列函数,它们以各种方式编码失败。例如:
在失败时返回f::A->Bool
False
失败时返回g::B->Maybe B'
Nothing
在失败时返回h::C->任一错误C'
Left…
Maybe
monad相同的方式链接这些操作,因此链接函数需要在继续下一个函数之前知道每个函数是否失败。为此,我编写了以下课程:
class Fail a where
isFail :: a -> Bool
instance Fail () where
isFail () = False
instance Fail Bool where -- a
isFail = not
instance Fail (Maybe a) where -- b
isFail = not . isJust
instance Fail (Either a b) where -- c
isFail (Left _) = True
isFail _ = False
但是,可能存在不一致的函数:
在失败时返回f':A->Bool
True
在失败时返回g':B->Maybe Error
(Just Error
)成功时无任何内容
在失败时返回h':C->任意一个C'错误
Right…
f'=not。f'
g'=(\case Nothing->Right();Just e->Left e)。g'
h'=(\case Left c->Right c;Right e->Left e)。h'
f
、g
、h
、f'
、g'
、和h'
,并让它们正常工作。他不会知道需要转换函数的返回类型,除非他查看正在组合的每个函数的语义,并检查它们是否与范围内的Fail
实例匹配。对于普通用户来说,这是一个冗长而微妙的过程,尤其是在类型推断绕过用户必须选择正确实例的情况下
这些函数不是在了解如何使用它们的情况下创建的。因此,我可以制作一个类型数据结果ab=Fail a | Success b
,并围绕每个函数制作包装。例如:
fR=(\case-True->suces();False->Fail())。f
f'R=(\case False->suces();True->Fail())。f'
gR=(\case Just a->success a;Nothing->Fail())。g
g'R=(\case Nothing->success();Just e->Fail e)。g'
hR=(\case Left e->Fail e;Right a->success a)。h
h'R=(\case Right e->Fail e;Left a->success a)。h'
f
,g
,h
,f'
,g'
,以及h'
。有没有更直接的方法?我想要的是一种确切的方式,来说明每个函数应该使用Fail
typeclass的哪个实例,即(使用上面给出的typeclass实例的名称),f
→ <代码>a,g
→ <代码>b,h
→ <代码>c和f'
→ <代码>a',g'
→ <代码>b',h'
→ c'
对于“无效”函数,其中a'
、b'
和c'
被定义为以下实例(与前面的实例重叠,因此您需要能够以某种方式按名称选择它们):
不过,这不一定要通过类型类来完成。也许除了使用类型类,还有其他方法可以做到这一点?不要这样做。Haskell的静态类型系统和引用透明性为您提供了非常有用的保证:您可以正确地确定某些特定值意味着相同的内容1,而不管它是如何产生的。与此无关的是,既没有易变性,也没有动态风格的表达式“运行时重新解释”,正如您所设想的任务所需要的那样 如果您在那里拥有的那些函数没有相应地遵循这样的规范,那么这是不好的。最好摆脱它们(至少,隐藏它们,只导出具有统一行为的重新定义的版本)。或者告诉用户,他们将不得不忍受查找每个产品的规格。但是,不要试图通过某种方式绕过这个定义不正确的特殊症状 一个简单的更改可以应用于“标记”函数,其中failure的意思与其他操作相反,就是让它们返回这样一个包装结果:
newtype Anti a = Anti { profail :: a }
instance (Anti a) => Fail (Anti a) where
isFail (Anti a) = not $ isFail a
思想:“同一件事”在一个可能非常抽象的意义上。没有必要让
Left
成为一个通用的“失败构造函数”,很明显,它是与第一个类型参数相关联的变量构造函数,这是而不是函子/单子实例操作的对象,从这一点上,它会自动得出“这意味着”一元应用程序失败。也就是说,当您选择了正确的类型时,内容应该几乎自动地明确无误;显然,当你只是这样做的时候,情况正好相反,所以也许你应该完全摆脱这些…如果你想把它们像单子一样连在一起(使用
do
符号),那么你需要将它们全部转换成一个单一的类型,然后你可以为其创建一个单子实例。您声明希望类型系统在没有提示或上下文的情况下,只知道函数的失败意味着什么。理论上,我可以有无限多个函数,每个函数返回一个表示失败的不同整数,编译器如何知道特定整数何时失败?它只有一个作为上下文的值。你不能指望编译器为你编写程序,否则我们都会使用Agda。是的,我不一定要把它变成monad,但它会是类似的。我不希望编译器知道哪些整数是失败的,我想以某种方式指出
newtype Anti a = Anti { profail :: a }
instance (Anti a) => Fail (Anti a) where
isFail (Anti a) = not $ isFail a