纯粹和受约束的一元函数的统一接口

时间:2018-01-15 19:03:54

标签: haskell polymorphism overloading typeclass

我想通过x类型变量创建重载函数,它可以统一这两种类型:

append :: A -> x -> A
append :: MonadThrow m => A -> x -> m A

在这种情况下,我应该写什么类型的课程?目前我有这样的事情:

class MyClasss (x :: *) (m :: * -> *) | x -> m where
    type MonadConstraint x :: (* -> *) -> Constraint
    append :: MonadConstraint x m => A -> x -> m A
  

我可以使用Identity monad模拟纯版本并创建帮助函数。

但是当我创建像这样的实例时:

instance MyClass X m where ...

我看到以下编译错误:

    • Illegal instance declaration for 'MyClass Text m'
        The coverage condition fails in class 'MyClass'
          for functional dependency: 'p -> m'
        Reason: lhs type 'X' does not determine rhs type 'm'
        Un-determined variable: m
    • In the instance declaration for 'MyClass X m'
   |
94 | instance MyClass X m where
   |          ^^^^^^^^^^^

我可以做些什么来抽象这两个函数?

1 个答案:

答案 0 :(得分:2)

我不确定我是否推荐这个,但它编译并运行,至少对于给定的情况。

{-# LANGUAGE TypeFamilies, FlexibleInstances, MultiParamTypeClasses,
             AllowAmbiguousTypes #-}

import Control.Monad.IO.Class

data A = A Int deriving Show
data X1 = X1
data X2 = X2

我们使返回类型由类型函数表示。

class MyClass (x :: *) (m :: * -> *) where
  type Ret x m :: *
  append :: A -> x -> Ret x m

如果X1没有导致monadic结果,我们会Ret X1 m非monadic。

instance MyClass X1 m where
  type Ret X1 m = A
  -- append :: A -> X1 -> A
  append a x = a

否则,我们将Ret X1 m monadic。

instance MonadIO m => MyClass X2 m where
  type Ret X2 m = m A
  -- append :: MonadIO m => A -> X2 -> m A
  append a x = liftIO (putStrLn "hi!") >> return a

缺点是这涉及不明确的类型,因此我们必须打开该扩展。但是,以下测试通过正常,因为GHC能够解决歧义。

test1 :: A
test1 = append (A 3) X1

上面,没有任何内容告诉GHC m是什么,但由于X1只有一个实例,因此不会出现错误。

test2 :: IO A
test2 = append (A 3) X2

同样为X2