Haskell的类型类与参数类型
问题描述:
我想如下定义一个特定函子:Haskell的类型类与参数类型
{-# 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
32,我想在c
类型的类型类MF
具有类型参数a
和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);
}
此外,在另一方面,过滤功能应该有一个类型:
mfilter :: (a -> Bool) -> MF c a b -> MF c a b
答
最直接的方式做到这一点,从您的代码开始,将是函数依赖添加到您的类型类:
{-# LANGUAGE FunctionalDependencies #-}
class MF c a b | c -> a, c -> b where
...
这本质上只是告诉编译器的类型的信息和b
已经包含在c
(因此可以在呼叫站点提取,因此a2
,b3
等将不会有歧义)。当您定义instance MF
时,如何提取此信息可以确定为GHC。虽然通常这种方式很好,但是我觉得为什么要这样做有点令人怀疑:如果c
总是有X a b
(X
是一个合适的data
-型函数,可以部分应用),那么为什么甚至在课堂上提及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 |守卫b | Elem a(MemoryMonad a b)' 我该如何让它成为这个类型类的一个实例? – jackb
@jackb'instance MF(MemoryMonad a b)where type ValType(MemoryMonad a b)= a;键入ErrType(MemoryMonad a b)= b' – user2407038