私は現在haskellにサーバーを構築しており、その言語の初心者として、新しいアプローチのzu Monadの構成を試してみたいと思います。アイデアは、私たちが根底にあるモナドを知らずに働くハスケルの型システムと戦わずにモナドを抽象化する方法は?
isGetRequest :: (SupportsRequests m r) => m Bool
isGetRequest = do
method <- liftRequests $ requestMethod
return $ method == GET
class (Monad m, RequestSupport r) => SupportsRequests m r | m -> r where
liftRequests :: r a -> m a
class (Monad r) => RequestSupport r where
requestMethod :: r Method
のようなライブラリのメソッドを書くことができるということです。もちろん、この例では、isGetRequestを(RequestSupport r)モナドで直接操作するだけで十分でしたが、私のライブラリはモナドに対して複数の制約を持つ可能性があります。しかし、私は同じモジュール内の異なる懸念のすべてを実装したくないし、別のモジュール(孤立したインスタンス)に分散させたくありません。 そのため、m個のモナドはSupports*
クラスのみを実装し、本当の懸念事項を他のモナドに委譲しています。
上記のコードは完全に機能するはずです(GHCのいくつかの言語拡張で)。私はエラーを取得する
class (Monad m, CRUDSupport c a) => SupportsCRUD m c a | m a -> c where
liftCRUD :: c x -> m x
class (Monad c) => CRUDSupport c a | c -> a where
list :: c [a] -- List all entities of type a
ません:型チェッカーがa
パラメータことを好きではないよう
Could not deduce (SupportsCRUD m c a0) from the context [...]
The type variable 'a0' is ambiguous [...]
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: liftCRUD [...]
は思え残念ながら、私はCRUD(削除読むアップデートを作成します)懸念を持ついくつかの問題を得ましたリフトCRUDの署名に直接発生しません。 a
は関数の依存関係から派生することができないため、これは理解できます。
私の脳の型チェッカーでは、AllowAmbiguousTypesを使用して、後でタイプa
を推測することは問題ではないことを教えています。CRUDに関するいくつかのメソッドがライブラリメソッドで実行されています。残念ながら、GHCは
bookAvailable :: (SupportsCRUD m c Book) => m Bool
bookAvailable = do
books <- liftCRUD (list :: c [Book]) -- I use ScopedTypeVariables
case books of
[] -> return False
_ -> return True
利回り
Could not deduce (SupportsCRUD m c0 a1) arising from a use of 'liftCRUD' [...]
The type variables c0, a1 are ambiguous [...]
例えば、この推論ステップを行うことができないようだ私がまだコンパイラについて推論することができませんようです。私はこの問題を解決する方法がありますか?あるいは、コンパイラが何を推測できるのかを理解するための少なくとも1つの方法はありますか?また、あなたはforall
とスコープになりたい変数をバインドする必要がありScopedTypeVariables
使用するには
よろしく、 bloxx
'SupportsCRUD'クラスの宣言には、3つの型変数、' m'、 'c'、' a'があります。あなたの例で、これらの3つの変数についてコンパイラが推測する値が何であるか、そしてその理由を教えてください。 –
あなたはあなたの資金で 'm a - > c'で何をしましたか?つまり、「cの選択は、型チェッカーが「m」と「a」だけに基づいてインスタンスを選択できるという効果を持つ特定の型「m」と「a」によって一意的に決定されます。文脈で、 'c'はあなたがインスタンスヘッドに置いたものに従います。 – jberryman
@jberryman実際には、モナドmと "CRUDエンティティ" aに対して、型チェッカーは一意のモナドc(これはCRUD操作をサポートするもの)を選択できることをコンパイラに伝えるべきです。 – bloxx