jac*_*ckb 3 haskell abstraction interface typeclass
我想定义一个特定的仿函数如下:
{-# 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
Run Code Online (Sandbox Code Playgroud)
我希望我的类型MF上的类型类型c具有类型参数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
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误:
haskell.hs:24:1:
Run Code Online (Sandbox Code Playgroud)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);
}
Run Code Online (Sandbox Code Playgroud)
另外,另一方面,过滤功能应该有一个类型:
mfilter :: (a -> Bool) -> MF c a b -> MF c a b
Run Code Online (Sandbox Code Playgroud)
从代码开始,最直接的方法是向类型类添加功能依赖:
{-# LANGUAGE FunctionalDependencies #-}
class MF c a b | c -> a, c -> b where
...
Run Code Online (Sandbox Code Playgroud)
这基本上只是告诉类型信息的编译器a,并b已经包含在c(,因此可以在调用点被提取,因此a2,b3等等不会有歧义).当你定义一个时,GHC可以确定如何准确地提取这些信息instance MF.虽然通常这工作得很好,我觉得有点可疑,为什么要这样来做:如果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
Run Code Online (Sandbox Code Playgroud)
或者,如果你真的想要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)
Run Code Online (Sandbox Code Playgroud)
这基本上等同于TypeFamilies解决方案,但是提供了更明确,更不神秘(尽管也更冗长)的界面.