这确实是一个初学者的问题,但是我在网络上或stackoverflow上都找不到任何有关它的信息。也许我只是搜索错误。.
我有一个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 Stackoverflow|]
main = warp 8080 App
如何将getHomeR
函数移到单独的文件中?在getHomeR
中,我需要访问App
,但是mkYesod "App"
需要访问getHomeR
。这看起来像是循环依赖性。但是以某种方式必须创建由多个源文件组成的yesod应用程序。
我可以要做的是将独立于App
的功能移动到单独的文件中。但是随着App
的增长和包含越来越多的功能,这变得不方便,因为所有顶级处理程序功能仍需要位于同一文件中。而且我不想使用yesod模板,因为我不知道它在做什么。
从评论中提出建议的解决方案:
您可以在单独的文件中定义功能,然后将其导入到Main中。这或多或少是在yesod-mysql堆栈模板中完成的。
错误消息:“由于使用'defaultLayout'而导致(Yesod site0)没有实例”。
当我在GetHomeR.hs中import Main
时,错误消息变为“歧义类型变量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)
这感觉不对。这是正确的方法吗?
答案 0 :(得分:3)
我终于自己解决了。
有时,您将需要在一个文件中声明路由,并在其他位置定义处理程序。例如,这是将整体文件分成较小部分的唯一方法。将此功能与mkYesodDispatch配对使用即可。
您必须创建一个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 Stackoverflow|]
mkYesod基本上类似于mkYesodData + mkYesodDispatch,不同之处在于,由于“阶段限制”,mkYesodData + mkYesodDispatch不能位于同一文件中(错误消息:“ GHC阶段限制:`resourcesApp'用于顶层接头,准引用或注释,并且必须导入,而不是在本地定义”)
在调用mkYesodDispatch
(或mkYesod
)时,所有路由处理程序(getHomeR,...)必须可见。