2017-07-05 85 views
2

我想在Haskell中實現一個DelayedJob(來自Rails世界)的端口。如何在運行時將對應的Haskell類型可用的JSON反序列化爲值?

這裏的類型類我有代表DelayedJob

class (FromJSON j, ToJSON j, FromJSON r, ToJSON r) => DelayedJob j r | j -> r where 
    serialise :: j -> Value 
    serialise = toJSON 

    deserialise :: Value -> Either String j 
    deserialise = parseEither parseJSON 

    runJob :: j -> AppM r 

這是我打算如何使用它:

createJob :: (DelayedJob j r) => j -> AppM JobId 

我越來越堅持寫一個相當普遍的invokeJob功能,將讀從jobs表中查看一行,查看jobs.jobtype列並調用runJob版本的正確版本(即runJob函數屬於正確的類型實例)。

我有以下,但它是完全的樣板:

data JobType = SyncContacts | SendEmail | SendSms deriving (Eq, Show, Generic) 

invokeJob :: JobId -> AppM() 
invokeJob jid = do 
    job <- fetchJob jid 
    case (job ^. jobtype) of 
    SyncContacts -> case (deserialise (job ^. jobdata) :: Either String SynContactsJob) of 
     Left e -> error e 
     Right j -> storeJobResult jid $ runAppM j 
    SendEmail -> case (deserialise (job ^. jobdata) :: Either String SendEmailJob) of 
     Left e -> error e 
     Right j -> storeJobResult jid $ runAppM j 
    SendSms -> case (deserialise (job ^. jobdata) :: Either String SendSms) of 
     Left e -> error e 
     Right j -> storeJobResult jid $ runAppM j 

從本質上講,是有辦法在運行時動態約束的具體類型deserialise功能,而不必寫了這麼多的樣板?

+0

不回答你的問題,但不應該定義'serialize'和'deserialize'函數,因爲它們似乎只能有一個實現,它是從約束派生的。 – bartavelle

回答

1

我不知道這樣的事情是否可以工作。我不知道你正在使用的框架。

let go :: forall jobtype . Job -> JobID -> .... 
    go job jid = 
     case deserialise (job ^. jobdata) :: Either String jobtype of 
      Left e -> error e 
      Right j -> storeJobResult jid $ runAppM j 
case (job ^. jobtype) of 
    SyncContacts -> go @ SynContactsJob job jid 
    SendEmail -> go @ SendEmail job jid 
    ... 

否則,我會試着看看單身人士是否可以提供幫助。如果您不想啓用不明確的類型&類型的應用程序,也可以使用代理。

+0

不知道這是我正在看的樣板清除。我試圖採取在https://gist.github.com/aaronlevin/4aa22bd9c79997029167概述的方法 - 任何幫助? –

1

我不願意提出它,但恕我直言,這裏要做的「正確的」事情是放棄類型安全性與一點運行時多態性。而不是一個類型,有不透明的Handler的種類,在你的情況下,它可能是像Value -> AppM()

只要將這些放在Map Type Handler或其他可以動態更新的行中; Type是您用來區分您的工作類型(即某種總和類型或最小安全類型,僅爲String)。當你拉出一份工作時,你可以在列表中查找適當的處理程序;該處理程序是不透明的,並且知道它負責哪些類型,所以用戶端不需要知道如何反序列化值。

這不是很聰明,但應該工作。

+0

不幸的是,這是迄今爲止我的最佳創意。我正在尋找比這更好的東西:) –

相關問題