2016-04-26 19 views
6

私はユーザーにダイアログを表示する方法を構築しています。タイプ推論 - Monadを推論できませんでした

data DialogConfig t m b e = 
    DialogConfig { _dialogConfig_title :: Dynamic t T.Text 
       , _dialogConfig_content :: b -> m (Dynamic t (Maybe b)) 
       , _dialogConfig_footer :: Dynamic t (Maybe b) -> m (Event t e) 
       } 
dialog :: MonadWidget t m => 
      DialogConfig t m b e -> Event t b -> m (Event t (DialogEvent e)) 

私は、例えばとしてそれを使用することができるように、dialog機能のためDialogConfigを初期化するために「デフォルト」のインスタンスのいくつかの種類を使用したいですdefaultConfig{_dialogConfig_content=content}。しかし、私は型推測で戦っている。これは動作します:

confirmDialog :: forall t m. MonadWidget t m => 
       T.Text -> Event t T.Text -> m (Event t()) 
... 
evt <- dialog 
     (DialogConfig { _dialogConfig_title = constDyn title 
         , _dialogConfig_content = content 
         , _dialogConfig_footer = buttons} 
         ) contentEvt 

をしかし、私はいくつかのデフォルトを使用する場合DialogConfig(例えばここではそれを直接インライン化)、それはしていません:

evt <- dialog 
     (DialogConfig { _dialogConfig_title = constDyn mempty 
        , _dialogConfig_content = const $ return $ constDyn Nothing 
        , _dialogConfig_footer = const $ return never } 
        { _dialogConfig_title = constDyn title 
        , _dialogConfig_content = content 
        , _dialogConfig_footer = buttons} 
        ) contentEvt 

エラーは以下のとおりです。

Could not deduce (Reflex t0) arising from a use of ‘constDyn’ from the context (MonadWidget t m) 
Could not deduce (Monad t1) arising from a use of ‘return’ from the context (MonadWidget t m) 

I ScopedTypeVariablesを使用し、confirmDialogのデフォルトの設定をDialogConfig t m a bと入力すれば動作しますが、それがなくても動作しませんか?タイプはむしろあいまいではないようです。

+1

[reflex-dom-contrib](https://github.com/reflex-frp/reflex-dom-contrib/blob/master/src/)には非常に良い(まだ実験的ですが)モーダルダイアログの形式があります – user2847643

+0

私たちは当面自分で実装することを決めました... – ondra

+3

エラーはおそらく、以前のレコード更新の値が使用されていないという事実のためです。自然にあいまいである。本質的な問題は、レコードの更新がレコードのタイプを変更できるということです。必要な型推論を取得するには、型を変更しない方法でレコード(レンズなど)を更新する方法を定義する必要があります。 – user2407038

答えて

4

コメントに記載されているように、問題はレコードの更新がの変更の変更(最初は驚くかもしれません)です。ここでGHCiの中のテストです:

> data T a = T { tA :: a } 
> let x = T "foo" 
> :t x 
x :: T [Char] 
> :t x { tA = True } 
x { tA = True } :: T Bool 

そこで、我々は、デフォルトを定義することはできません:確かに

> let def :: Read a => T a ; def = T (read "True") 
> :t def :: T Bool 
def :: T Bool :: T Bool 
> :t def { tA = 5 } 
    Could not deduce (Read t0) arising from a use of ‘def’ 
    The type variable ‘t0’ is ambiguous 

def上に任意のタイプのものであってもよいです。

可能な解決策は、T a -> T a継続機能を要求することによって、同じ種類の更新を強制する可能性があります。 d上記

> let defF :: Read a => (T a -> T a) -> T a ; defF f = f (T (read "True")) 
> :t defF (\d -> d { tA = False }) 
defF (\d -> d { tA = False }) :: T Bool 

建設により、更新後のレコードの同じ型を持っている必要があり、デフォルトです。

レンズでは、より良いアプローチがあるかもしれません。

+0

私はこれを答えとして受け入れます - はい、かなり論理的ですが、更新がタイプを変更できるという事実は予想外でした。 – ondra

関連する問題