Yesodにはまってると思いきやHaskellの文法にはまっていた

よくあるっちゃーよくあるんですが、Yesodを書いていてYesodの作法を理解していなくてはまっているのかと思いきや、実はHaskellの文法にやられていたという。

今回はこんなエラーが。

Handler/Bbs.hs:7:19:
    The first argument of ($) takes one argument,
    but its type `GGWidget master0 m0 ()' has none
    In the second argument of `($)', namely
      `do { setTitle "Bbs Index" } $ (widgetFile "bbs")'
    In the expression:
        defaultLayout $ do { setTitle "Bbs Index" } $ (widgetFile "bbs")
    In the expression:
      do { defaultLayout
         $   do { setTitle "Bbs Index" } $ (widgetFile "bbs") }
Starting development server...

dist/devel.hs:3:1:
    Failed to load interface for `Application':
      it is not a module in the current program, or in any known package.
Exit code: ExitFailure 1

エラーが出ている関数がこちら。

getBbsR :: Handler RepHtml
getBbsR = do
  defaultLayout $ do
    setTitle "Bbs Index"
    $ (widgetFile "bbs")

この関数の修正版がこちら。

getBbsR :: Handler RepHtml
getBbsR = do
  defaultLayout $ do
    setTitle "Bbs Index"
    $(widgetFile "bbs")

ちがいが分かりますか?
最終行の $ の後ろに空白があるかないかのちがいなんです。

なんでこれでエラーになるのか、理解できません。Haskellで、インデントの付け方がまずくてエラーになるのはよくあるのですが、空白の有無で意味が変わるなんてのは初めて。ましてや $ の引数を () で囲んで明示しているのに。

でも理解できなくても先に進むことはできます。当面、理解は置いておいて、前進!

その後・・・

その後、このエントリの一つ前のエントリでリンクした「できる!Template Haskell (完)」にきちんと書いてありました。

合成した構文木を埋め込むには、 $( ) で囲めばよいのです。

http://haskell.g.hatena.ne.jp/mr_konn/20111218/1324220725

そうだったのか!$っていう関数を適用してるのかと思ってたから理解できなかったんだな。なっとく。

ちなみに$()ってのは関数ではなくてTemplateHaskellにおける記法のようです。