如何修复编译re haskell刚性类型变量

oknrviil  于 2023-01-09  发布在  其他
关注(0)|答案(1)|浏览(128)

我有一个名为Step的聚合类型,并从它创建了一些具体的类型:

class (Eq q, User a, User b, User c) => (Step q a b c) where
  {-# MINIMAL performerA, performerB, performerC, completionDate  #-}
  performerA           :: Lens' q a
  performerB           :: Lens' q b
  performerC           :: Lens' q (Maybe c)

data Step1
makeLenses ''Step1
instance Step Step1 UserType1 UserType2 UserType3 where
  ...

data Step2
makeLenses ''Step2
instance Step Step2 UserType1 UserType2 UserType4 where
  ...

我的工厂函数接受一些参数,并返回一个步骤,该步骤对应于使用case表示的一些标准:

mkStep :: (User a, User b, User c, Step q b a c) 
       => Package a b
       -> b 
       -> Maybe c
       -> Either ValidationError q
mkStep package performer' nextPerformer' = do
  return step
  where
    step = case (package ^. currentPerformer . memberType, performer' ^. memberType, nextPerformer' ^. memberType) of 
            (MemberType3, MemberType2, MemberType4) 
              -> Step1 performer' (package ^. currentPerformer) nextPerformer'
            (MemberType3, MemberType2, MemberType1) 
              -> Step2 performer' (package ^. currentPerformer) nextPerformer'

关于构建Step时涉及的其他类型的一些额外信息:

data MemberType = MemberType1 
                | MemberType2
                | MemberType3
                | MemberType4
                deriving (Show, Eq)

class (Eq a, Show a) => User a where
  {-# MINIMAL memberType, userId #-}
  memberType  :: Lens' a MemberType
  userId      :: Lens' a MemberId

data UserType1
makeLenses ''UserType1
instance User UserType1 where
  ...
data UserType2
makeLenses ''UserType2
instance User UserType2 where
  ...
data UserType3
makeLenses ''UserType3
instance User UserType3 where
  ...
data UserType4
makeLenses ''UserType4
instance User UserType4 where
  ...

data Package a b = Package
    { _currentPerformer       :: a
    , _nextPerformer          :: Maybe b
    } deriving (Show, Eq)
makeLenses ''Package

然而,当我尝试构建代码时,我得到了以下结果:

> stack build
Building all executables for 'ss-model-ddd' once. After a successful build of all of them, only specified executables will be rebuilt.
ss-model-ddd> build (lib + exe)
Preprocessing library for ss-model-ddd-0.1.0.0..
Building library for ss-model-ddd-0.1.0.0..
[7 of 7] Compiling Steps

/home/aoaddeola/ss-model-ddd/src/Steps.hs:103:10: error:
    • Couldn't match expected type ‘q’
                  with actual type ‘Step2’
      ‘q’ is a rigid type variable bound by
        the type signature for:
          mkStep :: forall a b c q.
                    (User a, User b, User c, Step q b a c) =>
                    Package a b -> b -> Maybe c -> Either ValidationError q
        at src/Steps.hs:(96,1)-(100,34)
    • In the first argument of ‘return’, namely ‘step’
      In a stmt of a 'do' block: return step
      In the expression: do return step
    • Relevant bindings include
        mkStep :: Package a b
                  -> b -> Maybe c -> Either ValidationError q
          (bound at src/Steps.hs:101:1)
    |
103 |   return step
    |          ^^^^

/home/aoaddeola/ss-model-ddd/src/Steps.hs:109:18: error:
    • Couldn't match type ‘Step1’
                     with ‘Step2’
      Expected: Step2
        Actual: Step1
    • In the expression:
        Step1
          performer' (package ^. currentPerformer) nextPerformer'
      In a case alternative:
          (MemberType3, MemberType2, MemberType4)
            -> Step1
                 performer' (package ^. currentPerformer) nextPerformer'
      In the expression:
        case
            (package ^. currentPerformer . memberType, performer' ^. memberType, 
             nextPerformer' ^. memberType)
        of
          (MemberType3, MemberType2, MemberType1)
            -> Step2
                 performer' (package ^. currentPerformer) nextPerformer'
          (MemberType3, MemberType2, MemberType4)
            -> Step1
                 performer' (package ^. currentPerformer) nextPerformer'
    |
109 |               -> Step1 performer' (package ^. currentPerformer) nextPerformer'
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我发现很难找出问题所在。我的第一个罪魁祸首是我正在使用Lenses,它只在运行时可用(我猜)。
我们希望能找到解决这个问题的办法。

wqlqzqxt

wqlqzqxt1#

这其实和镜头没有什么关系,你写了一个mkStep函数,类似于:

mkFoo :: (Show q) => Bool -> q
mkFoo b = case b of True -> 'c'
                    False -> ()

换句话说,您声称mkStep将提供调用者请求的任何(严格的AKA用户指定的)类型Show q => q,而实际上您将提供由 * 您的 * 函数(而不是调用者)确定的q,其类型基于运行时输入。
这可以从两个方面来解释:你不能声称提供调用者想要的任何q,然后只提供一个特定的q(例如Step2);你也不能写一个case语句,根据一个单一类型(MemberType, MemberType, Membertype)的被检查者,计算出两种不同类型的表达式(Step1Step2)。

相关问题