首页 文章

Haskell类型参数类型

提问于
浏览
3

我想定义一个特定的仿函数如下:

{-# 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

我希望类型 c 上的类型类 MF 具有类型参数 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:无法演绎(MF c a2 b3)
由'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)
由'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
在haskell.hs:(24,1) - (35,28)
类型变量'a2','b3'是不明确的
检查'mfilter'时
具有推断类型'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'
可能原因:推断类型不明确

我想知道在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 回答

  • 5

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

    {-# LANGUAGE FunctionalDependencies #-}
    class MF c a b | c -> a, c -> b where
      ...
    

    这基本上只是告诉编译器 ab 的类型信息已经包含在 c 中(因此可以在调用站点提取,因此 a2b3 等不会是不明确的) . 当您定义 instance MF 时,可以通过GHC确定如何准确提取此信息 . 虽然通常这种方法效果很好,但我觉得为什么要这样做有点疑问:如果 c 始终具有 X a b 形式(并且 X 是一个可以部分应用的正确 data -type-函数),那么为什么甚至在课堂上提到 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
    

    或者,如果你真的希望 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)
    

    这基本上等同于 TypeFamilies 解决方案,但是提供了一个更明确,更隐蔽(尽管也更冗长)的界面 .

相关问题