Haskell类型参数类型

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具有类型参数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
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我想知道在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);
}
Run Code Online (Sandbox Code Playgroud)

另外,另一方面,过滤功能应该有一个类型:

mfilter :: (a -> Bool) -> MF c a b -> MF c a b
Run Code Online (Sandbox Code Playgroud)

lef*_*out 5

从代码开始,最直接的方法是向类型类添加功能依赖:

{-# 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型功能,可部分应用),那么为什么还要提ab在班主任?他们基本上是多余的.为什么不给类(种单一参数Type -> Type -> Type,然后可以)应用ab

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(这确实有意义!),我应该建议将类定义中ab类型存储为类型族:

{-# 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解决方案,但是提供了更明确,更不神秘(尽管也更冗长)的界面.

  • @jackb`实例MF(MemoryMonad ab),其中类型为ValType(MemoryMonad ab)= a; 类型ErrType(MemoryMonad ab)= b` (2认同)