data GsdCommand = CreateWorkspace { commandId :: CommandId , workspaceId ::WorkspaceId , workspaceName :: Text }
| RenameWorkspace { commandId :: CommandId , workspaceId ::WorkspaceId , workspaceNewName :: Text }
| SetGoal { commandId :: CommandId ,
workspaceId ::WorkspaceId ,
goalId :: GoalId ,
goalDescription :: Text} deriving Show
我想将一个特定的命令处理为一个功能, 例如使用伪代码:
{-# LANGUAGE DataKinds #-}
handle :: 'CreateWorkspace -> CommandDirective GsdState
我本以为可以将值构造函数提升为类型,但实际上我不知道该怎么做...
答案 0 :(得分:4)
解决方案1:不要幻想,请使用Haskell 98兼容类型
我建议的第一个解决方案是使用单独的记录类型。这不需要任何花哨的类型的系统黑客,并且避免了记录字段名称中隐含的部分功能。
type CommandId = ()
type WorkspaceId = ()
type Text = ()
data GsdCreate = GsdCreate { gsdcCommandId :: CommandId
, gsdcWorkspaceId :: WorkspaceId
, gsdcWorkspaceName :: Text
}
deriving (Show)
data GsdCommand = CreateWorkspace GsdCreate
| RenameWorkspace { commandId :: CommandId
, workspaceId ::WorkspaceId
, workspaceNewName :: Text }
| SetGoal { commandId :: CommandId ,
workspaceId ::WorkspaceId ,
goalDescription :: Text }
deriving (Show)
type CommandDirective a = Maybe a
type GsdState = ()
handle :: GsdCreate -> CommandDirective GsdState
handle = undefined
此外:实际上,我支持Haskell消除我们所知道的data
而改为:
Record
用于具有字段名称的单个构造函数类型data
,没有字段名称,但具有多个构造函数。解决方案2:使用GADT和DataKinds
对于您的示例,此解决方案有些过高,但是也许您的实际问题有一段代码中未提到的需求。这个想法是创建一个新的数据类型,为您的构造函数定义标记,并将这些构造函数用作GADT的类型:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
type CommandId = ()
type WorkspaceId = ()
type Text = ()
data Ty = Create | Rename | Set
data GsdCommand a where
CreateWorkspace :: CommandId -> WorkspaceId -> Text -> GsdCommand Create
RenameWorkspace :: CommandId -> WorkspaceId -> Text -> GsdCommand Rename
SetGoal :: CommandId -> WorkspaceId -> Text -> GsdCommand Set
type CommandDirective a = Maybe a
type GsdState = ()
handle :: GsdCommand Create -> CommandDirective GsdState
handle = undefined
答案 1 :(得分:2)
也许这种方法足以满足您的需求。以下是Either
类型的变体,但标记了L
(左)和R
(右)注解以及投影l
和r
。
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
module G where
data L
data R
data E d a b where
L :: {l :: a} -> E L a b
R :: {r :: b} -> E R a b
foo :: E L a b -> a
foo (L x) = x
函数foo
和投影l
仅对左值有效,而r
仅对右值有效。