具有参数化类型的Haskell类型类
我想定义一个特定的函子,如下所示:具有参数化类型的Haskell类型类,haskell,interface,typeclass,abstraction,Haskell,Interface,Typeclass,Abstraction,我想定义一个特定的函子,如下所示: {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} data ValOrError a b = Val a | Error b class MF c a b where mcons :: a -> c -> c merr :: b -> c mhead :: c -> ValOrError a b mtail :: c -
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data ValOrError a b = Val a | Error b
class MF c a b where
mcons :: a -> c -> c
merr :: b -> c
mhead :: c -> ValOrError a b
mtail :: c -> ValOrError c b
mfilter f e =
let h = mhead e in
let t = mtail e in
case h of
Error b -> e
Val a -> case (f a) of
True -> case t of
Error d -> mcons a (merr d)
Val b -> mcons a (mfilter f b)
False -> case t of
Error d -> merr d
Val b -> mfilter f b
我希望typec
上的typeclassMF
具有类型参数a
和b
。我尝试在这样的数据结构上定义一个过滤函数,如下所示:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data ValOrError a b = Val a | Error b
class MF c a b where
mcons :: a -> c -> c
merr :: b -> c
mhead :: c -> ValOrError a b
mtail :: c -> ValOrError c b
mfilter f e =
let h = mhead e in
let t = mtail e in
case h of
Error b -> e
Val a -> case (f a) of
True -> case t of
Error d -> mcons a (merr d)
Val b -> mcons a (mfilter f b)
False -> case t of
Error d -> merr d
Val b -> mfilter f b
但我得到了以下错误:
haskell.hs:24:1:
Could not deduce (MF c a2 b3)
arising from the ambiguity check for ‘mfilter’
from the context (MF c a5 b6,
MF c a4 b5,
MF c a4 b4,
MF c a4 b,
MF c a3 b6,
MF c a b6)
bound by the inferred type for ‘mfilter’:
(MF c a5 b6, MF c a4 b5, MF c a4 b4,
MF c a4 b, MF c a3 b6, MF c a b6) =>
(a4 -> Bool) -> c -> c
at haskell.hs:(24,1)-(35,28)
The type variables ‘a2’, ‘b3’ are ambiguous
When checking that ‘mfilter’
has the inferred type ‘forall b c a b1 a1 a2 b2 a3 b3.
(MF c a3 b3, MF c a2 b2, MF c a2 b1,
MF c a2 b, MF c a1 b3, MF c a b3) =>
(a2 -> Bool) -> c -> c’
Probable cause: the inferred type is ambiguous
我想知道在haskell中是否有更好的方法来说明类型c
总是将a
和b
作为类型参数。使用类似Java的语法:
public interface MF<A,B> {
MF<A,B> mcons(A head, MF<A,B> tail);
MF<A,B> merr(B error);
ValOrError<A,B> head(MF<A,B> e);
ValOrError<MF<A,B>,B> tail(MF<A,B> e);
}
从代码开始,最直接的方法是向类型类添加函数依赖项:
{-# LANGUAGE FunctionalDependencies #-}
class MF c a b | c -> a, c -> b where
...
这基本上只是告诉编译器,a
和b
的类型信息已经包含在c
中(因此可以在调用站点提取,因此a2
,b3
等不会含糊不清)。定义实例MF
时,GHC可以确定如何准确提取此信息。虽然这通常效果很好,但我发现你为什么要这样做有点疑问:如果c
总是有xab
的形式(而且X
是一个适当的数据类型的函数,可以部分应用),那么为什么还要在类标题中提到a
和b
?它们基本上是多余的。为什么不给类一个单独的参数(类型为Type->Type->Type
),然后应用于a
和b
class MF x where
mcons :: a -> x a b -> x a b
merr :: b -> x a b
mhead :: x a b -> ValOrError a b
mtail :: x a b -> ValOrError (x a b) b
或者,如果您确实希望c
具有种类Type
(这确实有道理!),我建议将a
和b
类型作为类型族存放在类定义中:
{-# LANGUAGE TypeFamilies #-}
class MF c where
type ValType c :: *
type ErrType c :: *
mcons :: ValType c -> c -> c
merr :: ErrType c -> c
mhead :: c -> ValOrError (ValType c) (ErrType c)
mtail :: c -> ValOrError c (ErrType c)
这基本上等同于TypeFamilies
解决方案,但提供了一个更明确、更不神秘(尽管也更详细)的接口。我有一个关于最后一个解决方案的问题,我最喜欢这个解决方案。如果我有以下数据data MemoryMonad a b=Lift b | Guard b | Elem a(MemoryMonad a b)
;类型ErrType(MemoryMonad a b)=b