提升数据记录类型

时间:2019-05-02 16:06:01

标签: haskell

假设我们具有以下数据类型

data GsdCommand =  CreateWorkspace { commandId :: CommandId , workspaceId ::WorkspaceId , workspaceName :: Text }
             | RenameWorkspace { commandId :: CommandId , workspaceId ::WorkspaceId , workspaceNewName :: Text }

我想要一个仅包含CreateWorkspace的函数:

{-# LANGUAGE DataKinds #-}
handle :: Offset ->
          `CreateWorkspace CommandId WorkspaceId Text  ->
          IO (CommandHandlingResult)

这就是我自然地做的方法,但是我遇到了以下编译器错误:

Expected a type, but‘ 'CreateWorkspace CommandId WorkspaceId Text’ has kind ‘GsdCommand’
Expected kind ‘CommandId’, but ‘CommandId’ has kind ‘*’
Expected kind ‘WorkspaceId’, but ‘WorkspaceId’ has kind ‘*’
Expected kind ‘Text’, but ‘Text’ has kind ‘*’

这是上下文:

{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
module Eventuria.GSD.Write.CommandConsumer.Handling.HandleGSDCommand (handleGSDCommand) where

import           Eventuria.Libraries.PersistedStreamEngine.Interface.PersistedItem

import           Eventuria.Libraries.CQRS.Write.CommandConsumption.Definitions
import           Eventuria.Libraries.CQRS.Write.CommandConsumption.CommandHandlingResult


import           Eventuria.GSD.Write.Model.WriteModel
import           Eventuria.GSD.Write.Model.Commands.Command
import           Eventuria.GSD.Write.CommandConsumer.Handling.CommandPredicates
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.CreateWorkspace          as CreateWorkspace
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.RenameWorkspace          as RenameWorkspace
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.SetGoal                  as SetGoal
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.RefineGoalDescription    as RefineGoalDescription
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.StartWorkingOnGoal       as StartWorkingOnGoal
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.PauseWorkingOnGoal       as PauseWorkingOnGoal
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.NotifyGoalAccomplishment as NotifyGoalAccomplishment
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.GiveUpOnGoal             as GiveUpOnGoal
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.ActionizeOnGoal          as ActionizeOnGoal
import qualified Eventuria.GSD.Write.CommandConsumer.Handling.Commands.NotifyActionCompleted    as NotifyActionCompleted

type GSDCommandHandler  = Maybe GsdWriteModel ->
                         (Persisted GsdCommand) ->
                         IO (CommandHandlingResult)

handleGSDCommand :: HandleCommand GsdWriteModel
handleGSDCommand writeModelMaybe
               PersistedItem {offset , item = command }
  | (isFirstCommand offset) && (not . isCreateWorkspaceCommand) command = return $ CommandRejected "CreateWorkspace should be the first command"
  | otherwise =   gsdCommandHandler writeModelMaybe PersistedItem {offset , item = (fromCommand command) }

gsdCommandHandler :: GSDCommandHandler
gsdCommandHandler
        writeModelMaybe
        PersistedItem {offset , item = gsdCommand } =
  case (writeModelMaybe, gsdCommand) of
     (Nothing        ,CreateWorkspace          {commandId, workspaceId, workspaceName})                   -> CreateWorkspace.handle          offset            commandId workspaceId workspaceName
     (Just writeModel,RenameWorkspace          {commandId, workspaceId, workspaceNewName})                -> RenameWorkspace.handle          offset writeModel commandId workspaceId workspaceNewName
     (Just writeModel,SetGoal                  {commandId, workspaceId, goalId, goalDescription})         -> SetGoal.handle                  offset writeModel commandId workspaceId goalId goalDescription
     (Just writeModel,RefineGoalDescription    {commandId, workspaceId, goalId, refinedGoalDescription})  -> RefineGoalDescription.handle    offset writeModel commandId workspaceId goalId refinedGoalDescription
     (Just writeModel,StartWorkingOnGoal       {commandId, workspaceId, goalId})                          -> StartWorkingOnGoal.handle       offset writeModel commandId workspaceId goalId
     (Just writeModel,PauseWorkingOnGoal       {commandId, workspaceId, goalId})                          -> PauseWorkingOnGoal.handle       offset writeModel commandId workspaceId goalId
     (Just writeModel,NotifyGoalAccomplishment {commandId, workspaceId, goalId})                          -> NotifyGoalAccomplishment.handle offset writeModel commandId workspaceId goalId
     (Just writeModel,GiveUpOnGoal             {commandId, workspaceId, goalId, reason})                  -> GiveUpOnGoal.handle             offset writeModel commandId workspaceId goalId reason
     (Just writeModel,ActionizeOnGoal          {commandId, workspaceId, goalId, actionId, actionDetails}) -> ActionizeOnGoal.handle          offset writeModel commandId workspaceId goalId actionId actionDetails
     (Just writeModel,NotifyActionCompleted    {commandId, workspaceId, goalId, actionId})                -> NotifyActionCompleted.handle    offset writeModel commandId workspaceId goalId actionId
     (_            ,_)                                                                                    -> return $ CommandRejected "Scenario not handle"

我必须对字段进行模式匹配并将其传递给句柄。...

2 个答案:

答案 0 :(得分:2)

DataKinds创建新的种类和值,但不更改值的类型。 CreateWorkspace值仍然具有类型GsdCommand,而不是类型'CreateWorkspace

一种选择是使用幻像类型,不需要DataKinds扩展名。

data CreateWorkspace
data RenameWorkspace

data GsdCommand t = GsdCommand CommandID WorkspaceID Text

handle :: Offset -> GsdCommand CreateWorkspace -> IO CommandHandlingResult
handle o (GsdCommand cmdID wkspID wkspName) = ...

答案 1 :(得分:0)

我已经在问题本身中添加了解决方案,但基本上我必须传递基于类的表达问题的方式,而不是使用基于交替的方式(使用Sum Types ...)并尝试使用促进价值...