我想按如下方式定义一个特定的仿函数:
{-# 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
我希望类型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
但是我收到了以下错误:
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
答案 0 :(得分:5)
从代码开始,最直接的方法是将功能依赖项添加到类型类中:
FATAL EXCEPTION: main
Process: com.example.framesss.myproject, PID: 2254
java.lang.IllegalStateException
at android.media.MediaRecorder.start(Native Method)
at com.example.framesss.myproject.Record$3.onClick(Record.java:138)
at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:157)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
这实际上只是告诉编译器{-# LANGUAGE FunctionalDependencies #-}
class MF c a b | c -> a, c -> b where
...
和a
的类型信息已经包含在b
中(因此可以在呼叫站点提取,因此{{1} },c
等不会含糊不清)。当您定义a2
时,可以通过GHC确定如何准确提取此信息。虽然通常这种方法效果很好,但我觉得为什么要这样做有点疑问:如果b3
始终具有instance MF
形式(c
是正确的{{} 1}} - 可以部分应用的类型函数),那为什么甚至在类头中提到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
解决方案,但是提供了更明确,更隐蔽(尽管也更冗长)的界面。