2

HTML DOM 要素を作成するための一連の関数を定義するReflex.Dom ライブラリを使用しています。

  • el要素を作成します
  • el'要素を作成して返す
  • elAttr指定された属性を持つ要素を作成します
  • elAttr'指定された属性を持つ要素を作成して返します

私は独自のウィジェット ライブラリを作成していますが、すべてのウィジェットに対してすべてのバリエーションを定義したくありません。そこで、同じ名前を使用する型クラスを作成しましたが、すべての関数を相互に定義し、各インスタンスで定義されるのはそのうちの 1 つだけです。

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}

module ElMaker where

import Data.Map (Map)
import qualified Data.Map as Map
import qualified Reflex.Dom as D

-- el: type of element to create
-- input: input parameter
-- output: return value
class (D.MonadWidget t m) => ElMaker t m el input output where
  el :: el -> input -> m output
  el e = elAttr e Map.empty

  elAttr :: el -> Map Text Text -> input -> m output
  elAttr e attrs input = snd <$> elAttr' e attrs input

  el' :: el -> input -> m (D.El t, output)
  el' e = elAttr' e Map.empty

  -- This is the only one to implement, yay!
  elAttr' :: el -> Map Text Text -> input -> m (D.El t, output)

elAttr'オリジナルを使用してテストするインスタンスを作成しました。出来た:

import Data.Text (Text)
import qualified Reflex.Dom as D

instance (D.MonadWidget t m) => ElMaker t m Text (m output) output where
  elAttr' = D.elAttr'

Button次に、ボタンがクリックされたときにイベントを返すウィジェット インスタンスを作成しました。出来た:

data Button = Button
instance (MonadWidget t m) => ElMaker t m Button (m input) (Event t ()) where
  elAttr' _ attrs contents = do
    (e, _) <- D.el' "button" contents
    return $ (e, D.domEvent D.Click e)

ウィジェットを構成できるようにしたいので、のインスタンスを使用して要素を作成するようにインスタンスを書き換えてみましButtonた。しかし、コンパイルに失敗します:TextElMaker

data Button = Button
instance (MonadWidget t m) => ElMaker t m Button (m input) (Event t ()) where
  elAttr' _ attrs contents = do
    (e, _) <- el' ("button" :: Text) contents
    return $ (e, D.domEvent D.Click e)

コンパイラ出力:

MDL.hs:119:15: error:
    • Could not deduce (ElMaker t m Text (m input) output0)
        arising from a use of ‘el'’
      from the context: MonadWidget t m
        bound by the instance declaration at MDL.hs:116:10-71
      The type variable ‘output0’ is ambiguous
      Relevant bindings include
        contents :: m input (bound at MDL.hs:117:19)
        elAttr' :: Button
                   -> Map.Map Text Text -> m input -> m (D.El t, Event t ())
          (bound at MDL.hs:117:3)
      These potential instance exist:
        instance MonadWidget t m => ElMaker t m Text (m output) output
          -- Defined in ‘ElMaker’
    • In a stmt of a 'do' block:
        (e, _) <- el' ("button" :: Text) contents
      In the expression:
        do { (e, _) <- el' ("button" :: Text) contents;
             return $ (e, D.domEvent D.Click e) }
      In an equation for ‘elAttr'’:
          elAttr' _ attrs contents
            = do { (e, _) <- el' ("button" :: Text) contents;
                   return $ (e, D.domEvent D.Click e) }

これは、関数がその型を制約する値で何もせず、コンパイラーが実際に具体的な型を持つことを望んでいるためだと思います。しかし、この型クラスは、その型パラメーターの値が何であるかを気にしません。とにかくこれをコンパイルする方法はありますか?

4

1 に答える 1