将Yesod应用程序源代码拆分为多个源文件

时间:2019-06-23 10:21:01

标签: haskell yesod

这确实是一个初学者的问题,但是我在网络上或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)

这感觉不对。这是正确的方法吗?

1 个答案:

答案 0 :(得分:3)

我终于自己解决了。

mkYesodData documentation说:

  

有时,您将需要在一个文件中声明路由,并在其他位置定义处理程序。例如,这是将整体文件分成较小部分的唯一方法。将此功能与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,...)必须可见。