我正在嘗試創建具有非常特定架構(有限狀態機)的電報機器人。例如,可能存在 (1) 狀態將運行某個函式,該狀態將回傳其他狀態或 (2) 狀態會將機器人移動到具有不同狀態的其他機器中。
所以我創建了類和兩種看起來像這樣的型別:
{-# LANGUAGE DeriveAnyClass, GADTs #-}
module Main where
class (Eq a) => TeleClass a
type BotView a = String -> a
data TeleState a where
TeleState :: TeleClass a => a -> BotView a -> TeleState a
TeleMachineChange :: (TeleClass a, TeleClass b) => a -> TeleMachine b -> TeleState a
data TeleMachine a = TeleMachine
{ defaultState :: a
, stateMachine :: [TeleState a]
}
然后 GHC 允許我創建一些看起來完全像我想要的 FSM:
data MainStates = MAIN_MENU | TASK_CHOOSING | CHANGE_VIEW | MODER_VIEW
deriving (TeleClass, Eq)
data AdminStates = ADMIN_MENU | PUBLISH_TASK
deriving (TeleClass, Eq)
data ModerStates = MODER_MENU | EDIT_TASK
deriving (TeleClass, Eq)
fMainMenu _ = TASK_CHOOSING
fChooseTask _ = CHANGE_VIEW
fAdminMenu _ = PUBLISH_TASK
fPublishTask _ = ADMIN_MENU
fModerMenu _ = EDIT_TASK
fEditTask _ = MODER_MENU
moderMachine = TeleMachine
{ defaultState = MODER_MENU
, stateMachine =
[ TeleState MODER_MENU fModerMenu
, TeleState EDIT_TASK fEditTask
]
}
adminMachine = TeleMachine
{ defaultState = ADMIN_MENU
, stateMachine =
[ TeleState ADMIN_MENU fAdminMenu
, TeleState PUBLISH_TASK fPublishTask
]
}
mainMachine = TeleMachine
{ defaultState = MAIN_MENU
, stateMachine =
[ TeleState MAIN_MENU fMainMenu
, TeleState TASK_CHOOSING fChooseTask
, TeleMachineChange CHANGE_VIEW adminMachine
, TeleMachineChange MODER_VIEW moderMachine
]
}
然后為了對 FSM 應用一些狀態,我添加了這個函式:
data MatchResult a b = Func a | Machine b | None
matchState :: (TeleClass a, TeleClass c) =>
[TeleState a] -> a -> MatchResult (BotView a) (TeleMachine c)
matchState (TeleState mState fFunc : stateMachine) state
| mState == state = Func fFunc
| otherwise = matchState stateMachine state
matchState (TeleMachineChange mState mMachine : stateMachine) state
| mState == state = Machine mMachine
| otherwise = matchState stateMachine state
matchState [] _ = None
編譯器抱怨它無法將型別 'b' 與 'c' 匹配:
? Couldn't match type ‘b’ with ‘c’
‘b’ is a rigid type variable bound by
a pattern with constructor:
TeleMachineChange :: forall a b.
(TeleClass a, TeleClass b) =>
a -> TeleMachine b -> TeleState a,
in an equation for ‘matchState’
at example.hs:70:13-45
‘c’ is a rigid type variable bound by
the type signature for:
matchState :: forall a c.
(TeleClass a, TeleClass c) =>
[TeleState a] -> a -> MatchResult (BotView a) (TeleMachine c)
at example.hs:(65,1)-(66,65)
Expected type: MatchResult (BotView a) (TeleMachine c)
Actual type: MatchResult (BotView a) (TeleMachine b)
? In the expression: Machine mMachine
In an equation for ‘matchState’:
matchState (TeleMachineChange mState mMachine : stateMachine) state
| mState == state = Machine mMachine
| otherwise = matchState stateMachine state
? Relevant bindings include
mMachine :: TeleMachine b (bound at example.hs:70:38)
matchState :: [TeleState a]
-> a -> MatchResult (BotView a) (TeleMachine c)
(bound at example.hs:67:1)
|
71 | | mState == state = Machine mMachine
| ^^^^^^^^^^^^^^^^
我嘗試使用 ExistentialQuantification 和 QuantifiedConstraints 擴展,但無法用它們解決這個問題。現在我不知道用像haskell這樣的語言實作這樣的東西是否可行。
uj5u.com熱心網友回復:
簽名
matchState :: (TeleClass a, TeleClass c) =>
[TeleState a] -> a -> MatchResult (BotView a) (TeleMachine c)
...這只是簡寫
matchState :: ? a c . (TeleClass a, TeleClass c) =>
[TeleState a] -> a -> MatchResult (BotView a) (TeleMachine c)
表示對于c呼叫者選擇的任何型別,此函式將能夠TeleMachine從輸入串列中獲取合適的。這似乎是一件很難的事情。
我認為您要表達的是“好的,我會嘗試在那里找到匹配的機器,但我不知道它的型別是什么”。那確實是一種存在主義
matchState :: ? a . ? c . (TeleClass a, TeleClass c) =>
[TeleState a] -> a -> MatchResult (BotView a) (TeleMachine c)
Haskell 不允許具有存在型別的函式,但您可以使MatchResult型別存在,類似于TeleMachineChange建構式的TeleMachine存在方式:
data MatchResult a where
Func :: a -> MatchResult a
Machine :: TeleClass b => b -> MatchResult a
None :: MatchResult a
matchState :: ? a . TeleClass a =>
[TeleState a] -> a -> MatchResult (BotView a)
matchState或者,您可以使用延續傳遞樣式偽造存在型別:
matchState :: ? a r . TeleClass a =>
[TeleState a]
-> a
-> (? c . TeleClass a
=> MatchResult (BotView a) (TeleMachine c) -> r)
-> r
matchState (TeleState mState fFunc : stateMachine) state φ
| mState == state = φ (Func fFunc)
| otherwise = matchState stateMachine state φ
matchState (TeleMachineChange mState mMachine : stateMachine) state
| mState == state = φ (Machine mMachine)
| otherwise = matchState stateMachine state φ
matchState [] _ = φ None
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/495984.html
標籤:哈斯克尔
下一篇:如何在GHCi中使用模式匹配?
