Разделить исходный код приложения yesod на несколько исходных файлов - PullRequest
2 голосов
/ 23 июня 2019

Это действительно вопрос новичка, но я не могу найти что-либо об этом в Интернете или в 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.

сообщение об ошибке: «Нет экземпляра для (Yesod site0), возникающего из-за использования defaultLayout».
И когда я import Main в GetHomeR.hs, сообщение об ошибке становится «Переменная типа неопределенности site0' arising from a use of defaultLayout '».
И когда я добавляю getHomeR :: Handler Html, он на мгновение компилируется, но: теперь мне нужно import GetHomeR из Main.hs. И GHC жалуется с предупреждением о циклической зависимости:

Module imports form a cycle:
         module `Main' (app\Main.hs)
        imports `GetHomeR' (app\GetHomeR.hs)
  which imports `Main' (app\Main.hs)

это не правильно. Это правильный способ сделать это?

1 Ответ

3 голосов
/ 23 июня 2019

Я наконец-то понял это сам.

В документации mkYesodData написано:

Иногда вам захочется объявить ваши маршруты в одном файле.и определить ваши обработчики в другом месте.Например, это единственный способ разбить монолитный файл на более мелкие части.Используйте эту функцию в паре с mkYesodDispatch, чтобы сделать именно это.

Вы должны создать модуль Foundation, в котором живут экземпляр App и Yesod:

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 »используется в соединении верхнего уровня, квази-кавычке или аннотации и должно быть импортировано, а не определено локально»)

Все обработчики маршрута (getHomeR, ...) должен быть виден в точке, где вызывается mkYesodDispatch (или mkYesod).

...