将yesod app源码拆分成多个源文件
Split yesod app source code into multiple source files
这确实是一个新手问题,但我在网上或 Whosebug 上找不到任何相关信息。可能是我搜索错了..
我有一个 yesod 应用程序,其中所有内容都在一个文件中,但我不知道如何将函数移动到单独的文件中。这是一个最小的例子:
{-# 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 Whosebug|]
main = warp 8080 App
如何将 getHomeR
函数移动到一个单独的文件中?在 getHomeR
中,我需要访问 App
,但 mkYesod "App"
需要访问 getHomeR
。这看起来像一个循环依赖。但不知何故,必须有可能创建由多个源文件组成的 yesod 应用程序。
我可以做的是将独立于App
的功能移动到单独的文件中。但是当 App
增长并包含越来越多的功能时,这就变得不方便了,因为所有顶级处理函数仍然需要在同一个文件中。而且我不想使用yesod模板,因为我不明白它在做什么。
解决评论中提出的解决方案:
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.
错误信息:"No instance for (Yesod site0) arising from a use of `defaultLayout'".
而当我在GetHomeR.hs中import Main
时,错误信息就变成了"Ambiguous type variable site0' arising from a use of
defaultLayout'".
当我添加 getHomeR :: Handler Html
时,它编译了一会儿,但是:现在我必须从 Main.hs 到 import GetHomeR
。 GHC 抱怨循环依赖的警告:
Module imports form a cycle:
module `Main' (app\Main.hs)
imports `GetHomeR' (app\GetHomeR.hs)
which imports `Main' (app\Main.hs)
这感觉不对。这是正确的做法吗?
我终于自己弄明白了。
Sometimes, you will want to declare your routes in one file and define your handlers elsewhere. For example, this is the only way to break up a monolithic file into smaller parts. Use this function, paired with mkYesodDispatch, to do just that.
您必须在 App
和 Yesod 实例所在的位置创建一个 Foundation 模块:
Foundation.hs:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Foundation where
import Yesod
data App = App
mkYesodData "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
在你的Main.hs中,你调用路由:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import Yesod
import Foundation
import GetHomeR (getHomeR)
mkYesodDispatch "App" resourcesApp
main = warp 8080 App
它又从 GetHomeR 模块调用 getHomeR。 GetHomeR.hs:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module GetHomeR (getHomeR) where
import Yesod
import Foundation
getHomeR :: Handler Html
getHomeR = defaultLayout $ toWidget [hamlet|Hello Whosebug|]
mkYesod 基本上类似于 mkYesodData + mkYesodDispatch,区别在于 mkYesodData + mkYesodDispatch 不能在同一个文件中,因为 "stage restriction"(错误消息:"GHC stage restriction: `resourcesApp' is used in a top-level splice, quasi-quote, or annotation, and must be imported, not defined locally")
所有路由处理程序(getHomeR,...)必须在调用 mkYesodDispatch
(或 mkYesod
)的位置可见。
这确实是一个新手问题,但我在网上或 Whosebug 上找不到任何相关信息。可能是我搜索错了..
我有一个 yesod 应用程序,其中所有内容都在一个文件中,但我不知道如何将函数移动到单独的文件中。这是一个最小的例子:
{-# 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 Whosebug|]
main = warp 8080 App
如何将 getHomeR
函数移动到一个单独的文件中?在 getHomeR
中,我需要访问 App
,但 mkYesod "App"
需要访问 getHomeR
。这看起来像一个循环依赖。但不知何故,必须有可能创建由多个源文件组成的 yesod 应用程序。
我可以做的是将独立于App
的功能移动到单独的文件中。但是当 App
增长并包含越来越多的功能时,这就变得不方便了,因为所有顶级处理函数仍然需要在同一个文件中。而且我不想使用yesod模板,因为我不明白它在做什么。
解决评论中提出的解决方案:
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.
错误信息:"No instance for (Yesod site0) arising from a use of `defaultLayout'".
而当我在GetHomeR.hs中import Main
时,错误信息就变成了"Ambiguous type variable site0' arising from a use of
defaultLayout'".
当我添加 getHomeR :: Handler Html
时,它编译了一会儿,但是:现在我必须从 Main.hs 到 import GetHomeR
。 GHC 抱怨循环依赖的警告:
Module imports form a cycle:
module `Main' (app\Main.hs)
imports `GetHomeR' (app\GetHomeR.hs)
which imports `Main' (app\Main.hs)
这感觉不对。这是正确的做法吗?
我终于自己弄明白了。
Sometimes, you will want to declare your routes in one file and define your handlers elsewhere. For example, this is the only way to break up a monolithic file into smaller parts. Use this function, paired with mkYesodDispatch, to do just that.
您必须在 App
和 Yesod 实例所在的位置创建一个 Foundation 模块:
Foundation.hs:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Foundation where
import Yesod
data App = App
mkYesodData "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
在你的Main.hs中,你调用路由:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import Yesod
import Foundation
import GetHomeR (getHomeR)
mkYesodDispatch "App" resourcesApp
main = warp 8080 App
它又从 GetHomeR 模块调用 getHomeR。 GetHomeR.hs:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module GetHomeR (getHomeR) where
import Yesod
import Foundation
getHomeR :: Handler Html
getHomeR = defaultLayout $ toWidget [hamlet|Hello Whosebug|]
mkYesod 基本上类似于 mkYesodData + mkYesodDispatch,区别在于 mkYesodData + mkYesodDispatch 不能在同一个文件中,因为 "stage restriction"(错误消息:"GHC stage restriction: `resourcesApp' is used in a top-level splice, quasi-quote, or annotation, and must be imported, not defined locally")
所有路由处理程序(getHomeR,...)必须在调用 mkYesodDispatch
(或 mkYesod
)的位置可见。