This is really a beginner question, but I cannot find anything about it on the web or on stackoverflow. Maybe I just searched wrong..
I have a yesod application where everything is in one file, and I cannot figure out how to move the functions into separate files. Here is a minimal example:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import Yesod
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
getHomeR = defaultLayout $ toWidget [hamlet|Hello Stackoverflow|]
main = warp 8080 App
How do I move the getHomeR
function into a separate file? In getHomeR
, I need access to App
, but mkYesod "App"
needs access to getHomeR
. This looks like a cyclic dependency. But somehow it must be possible to create yesod applications consisting of more than one source file.
What I can do is move functionality that is independent of App
into separate files. But when App
grows and contains more and more functionality, this becomes inconvenient, because all top level handler functions still need to be in the same file. And I don't want to use the yesod template, because I don't understand what it is doing.
to address a proposed solution from the comments:
You can define the functions in your separate files, and import these in the Main. This is more or less how it is done in the yesod-mysql stack template.
error message: "No instance for (Yesod site0) arising from a use of `defaultLayout'".
And when I import Main
in GetHomeR.hs, the error message becomes "Ambiguous type variable site0' arising from a use of
defaultLayout'".
And when I add a getHomeR :: Handler Html
, it compiles for a moment, but: now I have to import GetHomeR
from Main.hs . And GHC complains with a warning about a cyclic dependency:
Module imports form a cycle:
module `Main' (app\Main.hs)
imports `GetHomeR' (app\GetHomeR.hs)
which imports `Main' (app\Main.hs)
this doesn't feel right. Is this the right way to do it?
Main
. This is more or less how it is done in theyesod-mysql
stack template. As long asgetHomeR
is in the scope of theparseRoutes
you are fine, so with a simpleimport
you put these in scope. – Willem Van Onsemdata App = App
andinstance Yesod App
in aFoundation.hs
file, then you can import that in theHandler.hs
file(s), and then you import these handler's in theMain.hs
file where you thus import theApp
and theHandler
s. – Willem Van OnsemmkYesod "App"
call? Actual working source code would be very appreciated :) – Michael