我有一個函式型別宣告
f :: MonadHandler m => SqlPersistT m ()
我想轉換成
f :: MonadHandlerDB m => m ()
我嘗試了我能想到的一切來定義約束 MonadHandlerDB,但無法獲得它或函式型別宣告來編譯,例如:
class (forall a . (MonadHandler m, m ~ SqlPersistT a)) => MonadHandlerDB m
class MonadHandlerDB m
instance MonadHandler a => MonadHandlerDB (SqlPersistT a)
type MonadHandlerDB m = forall a . (MonadHandler a, m ~ SqlPersistT a)
type MonadHandlerDB = forall a . (MonadHandler a => m ~ SqlPersistT a)
type MonadHandlerDB m = forall a . (MonadHandler a => m ~ SqlPersistT a)
錯誤之一:
Couldn't match type `m' with `ReaderT backend0 m0
`m' is a rigid type variable bound by
the type signature for:
f:: forall (m :: * -> *).
MonadHandlerDB m =>
m ()
SqlPersistT 定義為
type SqlPersistT = ReaderT SqlBackend
我如何表達這個約束?
uj5u.com熱心網友回復:
我認為這實作了你想要的:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
import Control.Monad.Trans.Reader (ReaderT (ReaderT))
import Database.Persist.Sql (SqlPersistT)
import Yesod.Core (MonadHandler)
f :: MonadHandlerDB m => m ()
f = undefined
class (MonadHandler (Sub m), m ~ SqlPersistT (Sub m)) => MonadHandlerDB m where
type Sub m :: * -> *
instance MonadHandler m => MonadHandlerDB (SqlPersistT m) where
type Sub (SqlPersistT m) = m
但是請注意,我認為這在實踐中確實不太好使用。它看起來好像m是完全多型的,但實際上,它只能是內部的某個 monad SqlPersistT。
約束很強大,但我認為這樣的約束很可能會迷惑用戶。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/387026.html
