Haskell类型参数类型

时间:2016-11-27 19:08:43

标签: 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 -> ValOrError c b

我希望类型MF上的类型类c具有类型参数ab。我尝试在如下数据结构上定义过滤函数:

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总是有ab作为类型参数。使用类似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

1 个答案:

答案 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 bX?他们基本上是多余的。为什么不给这个类一个参数(种类data),然后应用ab

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解决方案,但是提供了更明确,更隐蔽(尽管也更冗长)的界面。