Вопрос

I have a Yesod application in which the entire web portion of the application was defined in one file, and it has grown to the size that I need to separate things out.

I want to set up a hirearchy like this:

web/Handlers/Group1
             Group2
web/Foundation
web/Main

This is similar to how the code for the Haskellers website is set up. However, I can't figure out how the Haskellers website actually works. When I set things up, my handlers in Group1 need to import Foundation to get the Foundation class and to get a list of other routes, because some of my handlers redirect to different parts of the app. But my Foundation won't compile because it wants to find the route handlers that are defined in Group1, Group2, etc.

This is forcing me into a circular import, which obviously won't work. When I read the Haskellers code, the Foundation module does not import any of the Handler modules.

What is the trick to make this work?


Update

Following Michael Snoyman's answer, I've replaced my call to mkYesod with separate calls to myYesodData and mkYesodDispatch. GHC complains, of course, if I do both in one file, so I separated stuff out in the first stage of a refactoring:

  • All of my code from Main.hs, which was all of the code of the web portion of the application, I moved to WebApp.hs
  • I moved the main function from WebApp.hs back into Main.hs
  • In WebApp.hs I call mkYesodData
  • In Main.hs I call mkYesodDispatch

And the linker fails now. When compiling Main, the first module it finds in the import list that it is in this project and not in a library fails to link like so:

web/Main.hs:1:1:
    cannot find normal object file `dist/build/invoicedb/invoicedb-tmp/WebApp.o'
    while linking an interpreted expression

If I drop mkYesodDispatch and mkYesodData and return to mkYesod, even using this same file structure, the build proceeds perfectly.

So, to review, here are my files:

web/Main.hs:

  • The main function
  • The call to mkYesodDispatch

config/routes:

  • plain text routing, just like in the scaffold app

web/WebApp.hs:

  • My App structure
  • mkYesodData
  • instance Yesod App
  • instance YesodAuth App
  • instance RenderMessage App FormMessage
  • All of my routing handlers

I have created a trivial example that illustrates this issue: https://bitbucket.org/savannidgerinel/yesod-decomposition/src/

[2 of 3] Compiling Dispatch         ( src/Dispatch.hs, dist/build/yesod-decomposition/yesod-decomposition-tmp/Dispatch.p_o )
src/Dispatch.hs:1:1:
    cannot find normal object file `dist/build/yesod-decomposition/yesod-decomposition-tmp/Foundation.o'
    while linking an interpreted expression

If you edit the code, commenting out mkYesodDispatch in Dispatch.hs, and replacing mkYesodData with mkYesod in Foundation.hs, the code will compile successfully.

Note, I'm using yesod-1.2.4 for this. If 1.2.6 solves it, then I will get my team upgraded.

Это было полезно?

Решение

I'm guessing your code is using a call to mkYesod. In order to make a split into multiple modules, you'll instead need to use mkYesodData and mkYesodDispatch as is done in the scaffolding site. For more information on this, please see the scaffolding chapter. It shouldn't be too difficult to adapt this technique to work with an existing codebase.

Другие советы

This looks like a bug in your .cabal file. Make sure that you tell cabal that you are using Template Haskell:

executable yesod-decomposition
   ..
   other-extensions: TemplateHaskell

So that it knows to build the right object files in the right order.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top