2011-11-05 26 views
7

मैं Happstack, चोरी, और वेब मार्गों, का उपयोग करते हुए एक आवेदन सर्वर लिखने की कोशिश कर रहा हूँ, लेकिन पता लगाना splices पहुँच मानों से ही शुरू नहीं है यह बताने के लिए कि कैसे परेशानी हो रही हूँ मेरे आवेदन के मोनैड ढेर।का उपयोग करते हुए मान नहीं टेम्पलेट्स

  • पैरामीटर वेब मार्गों के माध्यम से URL पथ से निकाला:

    दो स्थितियों में, जहां इस आता हैं। उचित हैंडलर को अनुरोध करते समय ये एक प्रकार-सुरक्षित यूआरएल पर पैटर्न-मिलान से आते हैं।

  • सत्र जानकारी। यदि अनुरोध एक नए सत्र के लिए है, तो मैं अनुरोध में कुकी से सत्र पहचानकर्ता नहीं पढ़ सकता (क्योंकि ऐसी कोई कुकी अभी तक मौजूद नहीं है), और यदि आवश्यक हो तो मैं एक नया सत्र बनाने के लिए स्प्लिसेस का उपयोग नहीं कर सकता, तब से यदि एक से अधिक स्प्लिस इसे करने की कोशिश करता है, तो मैं एक ही अनुरोध के लिए कई नए सत्र तैयार करता हूं। लेकिन अगर मैं वेब-रूट सामग्री दर्ज करने से पहले सत्र बनाता हूं, तो सत्र मोनैड के बाहर सत्र मौजूद है।/

    • /भाज्य/nn
    • के भाज्य आउटपुट/str आउटपुट रिवर्स str:

    निम्न नमूना कार्यक्रम निम्न URL की सेवा करने की कोशिश करता है पर विचार करें पीछे की ओर

चूंकि क्वेरी स्ट्रिंग के बजाय यूआरएल पथ में पैरामीटर दिखाई देता है, इसलिए यह सर्वरपार्टट मोनैड से आने के बजाय वेब-रूट्स के माध्यम से निकाला जाता है। वहां से, पैरामीटर को कहीं भी रखने का कोई स्पष्ट तरीका नहीं है जहां स्प्लिस इसे देख सकते हैं, क्योंकि उनके पास केवल एप्लिकेशन मोनैड तक पहुंच है।

इकाई ढेर पर कहीं एक ReaderT चिपके की स्पष्ट समाधान दो समस्याएं हैं:

  • एक ReaderT होने ऊपर ServerPartT इकाई ढेर के Happstack भागों छुपाता है, के बाद से ReaderT ServerMonad, FilterMonad को लागू नहीं करता है, इत्यादि
  • यह मानता है कि मैं जिन सभी पृष्ठों की सेवा कर रहा हूं, वे एक ही प्रकार के पैरामीटर लेते हैं, लेकिन इस उदाहरण में, फैक्टोरियल एक इंट चाहता है लेकिन रिवर्स स्ट्रिंग चाहता है। लेकिन दोनों पेज हैंडलरों के लिए एक ही टेम्पलेट डायरेक्टरी का उपयोग करने के लिए, रीडर को उसी प्रकार के मूल्य को ले जाने की आवश्यकता होगी।

स्नैप दस्तावेज़ों पर ध्यान देने से, ऐसा लगता है कि स्नैप हैंडल पैरामीटर को प्रभावी ढंग से क्वेरी स्ट्रिंग में कॉपी करके यूआरएल पथ में पैरामीटर हैंडल करता है, जो समस्या को दूर करता है। लेकिन यह हैप्स्टैक और वेब-रूट्स के साथ एक विकल्प नहीं है, और इसके अलावा, एक ही मान निर्दिष्ट करने के लिए यूआरएल के दो अलग-अलग तरीकों से मुझे सुरक्षा के अनुसार एक बुरा विचार माना जाता है।

तो, क्या गैर-अनुप्रयोग-मोनैड अनुरोध डेटा को विभाजित करने के लिए एक "उचित" तरीका है, या क्या मुझे हेस्ट को त्यागने और ब्लेज़-एचटीएमएल जैसे कुछ उपयोग करने की आवश्यकता है, जहां यह कोई मुद्दा नहीं है? मुझे लगता है कि मुझे कुछ स्पष्ट याद आ रहा है, लेकिन यह पता नहीं लगा सकता कि यह क्या हो सकता है।

उदाहरण कोड:

{-# LANGUAGE TemplateHaskell #-} 

import Prelude hiding ((.)) 

import Control.Category ((.)) 
import Happstack.Server (Response, ServerPartT, nullConf, ok, simpleHTTP) 
import Happstack.Server.Heist (render) 
import Text.Boomerang.TH (derivePrinterParsers) 
import Text.Templating.Heist (Splice, bindSplices, emptyTemplateState, getParamNode) 
import Text.Templating.Heist.TemplateDirectory (TemplateDirectory, newTemplateDirectory') 
import Web.Routes (RouteT, Site, runRouteT) 
import Web.Routes.Boomerang (Router, anyString, boomerangSite, int, lit, (<>), (</>)) 
import Web.Routes.Happstack (implSite) 

import qualified Data.ByteString.Char8 as C 
import qualified Data.Text as T 
import qualified Text.XmlHtml as X 

data Sitemap = Factorial Int 
      | Reverse String 

$(derivePrinterParsers ''Sitemap) 

-- Conversion between type-safe URLs and URL strings. 
sitemap :: Router Sitemap 
sitemap = rFactorial . (lit "factorial" </> int) 
     <> rReverse . (lit "reverse" </> anyString) 

-- Serve a page for each type-safe URL. 
route :: TemplateDirectory (RouteT Sitemap (ServerPartT IO)) -> Sitemap -> RouteT Sitemap (ServerPartT IO) Response 
route templates url = case url of 
         Factorial _num -> render templates (C.pack "factorial") >>= ok 
         Reverse _str -> render templates (C.pack "reverse") >>= ok 

site :: TemplateDirectory (RouteT Sitemap (ServerPartT IO)) -> Site Sitemap (ServerPartT IO Response) 
site templates = boomerangSite (runRouteT $ route templates) sitemap 

-- <factorial>n</factorial> --> n! 
factorialSplice :: (Monad m) => Splice m 
factorialSplice = do input <- getParamNode 
        let n = read . T.unpack $ X.nodeText input :: Int 
        return [X.TextNode . T.pack . show $ product [1 .. n]] 

-- <reverse>text</reverse> --> reversed text 
reverseSplice :: (Monad m) => Splice m 
reverseSplice = do input <- getParamNode 
        return [X.TextNode . T.reverse $ X.nodeText input] 

main :: IO() 
main = do templates <- newTemplateDirectory' path . bindSplices splices $ emptyTemplateState path 
      simpleHTTP nullConf $ implSite "http://localhost:8000" "" $ site templates 
    where splices = [(T.pack "factorial", factorialSplice), (T.pack "reverse", reverseSplice)] 
      path = "." 

भाज्य।TPL:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
     <meta charset="utf-8"/> 
     <title>Factorial</title> 
    </head> 
    <body> 
     <p>The factorial of 6 is <factorial>6</factorial>.</p> 
     <p>The factorial of ??? is ???.</p> 
    </body> 
</html> 

reverse.tpl:

func :: a -> m b 

क्योंकि हास्केल शुद्ध है और एक मजबूत स्थिर प्रकार प्रणाली है, डेटा में इस्तेमाल किया:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
     <meta charset="utf-8"/> 
     <title>Reverse</title> 
    </head> 
    <body> 
     <p>The reverse of "<tt>hello world</tt>" is "<tt><reverse>hello world</reverse></tt>".</p> 
     <p>The reverse of "<tt>???</tt>" is "<tt>???</tt>".</p> 
    </body> 
</html> 

उत्तर

4

निम्नलिखित फार्म के साथ एक समारोह पर विचार करें यह कार्य केवल तीन स्थानों से आ सकता है: वैश्विक प्रतीकों जो दायरे या आयातित हैं, पैरामीटर ('ए'), और मोनैड संदर्भ 'एम'। तो आपके द्वारा वर्णित समस्या हेस्ट के लिए अद्वितीय नहीं है, यह हास्केल का उपयोग करने का एक तथ्य है।

यह आपकी समस्या को हल करने के कुछ तरीकों का सुझाव देता है। एक ऐसा है जो आपको अपने स्प्लिस फ़ंक्शंस में तर्क के रूप में आवश्यक डेटा को पास करना है। कुछ इस तरह:

factorialSplice :: Int -> TemplateMonad (RouteT Sitemap (ServerPartT IO)) [X.Node] 
factorialSplice n = return [X.TextNode . T.pack . show $ product [1 .. n]] 

स्नैप में हम एक समारोह renderWithSplices कहा जाता है कि आप कुछ splices बाँध सही इससे पहले कि आप टेम्पलेट प्रस्तुत करना देता है कि है। आप इस तरह के फ़ंक्शन का उपयोग उस लाइन पर दाएं विभाजन को बांधने के लिए कर सकते हैं जहां आपके पास वर्तमान में "टेम्पलेट प्रस्तुत करना" है।

दूसरा दृष्टिकोण अंतर्निहित मोनड का उपयोग कर रहा है। आप कहते हैं कि "कहीं भी पैरामीटर डालने का कोई स्पष्ट तरीका नहीं है जहां स्प्लिसेस इसे देख सकते हैं, क्योंकि उनके पास केवल एप्लिकेशन मोनैड तक पहुंच है।" मेरे दिमाग में, "एप्लिकेशन मोनैड" तक पहुंच रखने के लिए आपको यह सामान स्प्लिसेस के अंदर लाने की ज़रूरत है। तो मेरा दूसरा सुझाव इसका उपयोग करना है। यदि आपके द्वारा उपयोग किए जा रहे एप्लिकेशन मोनैड में वह डेटा नहीं है, तो यह उस मोनैड की कमी है, न कि एक समस्या है।

जैसा कि आप उपरोक्त प्रकार के हस्ताक्षर में देख सकते हैं, टेम्पलेटमोनाड एक मोनैड ट्रांसफार्मर है जहां अंतर्निहित मोनड है (रूट साइटमैप (सर्वरपार्ट आईओ))। यह एक साधारण लिफ्ट के माध्यम से अंतर्निहित मोनैड में सबकुछ तक स्प्लिस पहुंच प्रदान करता है। मैंने वेब-रूट का कभी भी उपयोग नहीं किया है, लेकिन ऐसा लगता है कि उस साइटमैप पर जाने के लिए रूट रूट होना चाहिए। के निम्नलिखित समारोह मान लेते हैं मौजूद है:

getUrlData :: RouteT url m url 

तो फिर तुम लिखने के लिए सक्षम होना चाहिए: आप

factorialArgSplice :: TemplateMonad (RouteT Sitemap (ServerPartT IO)) [X.Node] 
factorialArgSplice = do 
    url <- lift getUrlData 
    return $ case url of 
     Factorial n -> [X.TextNode . T.pack . show $ n] 
     _ -> [] 

तब:

factorialSplice :: TemplateMonad (RouteT Sitemap (ServerPartT IO)) [X.Node] 
factorialSplice = do 
    url <- lift getUrlData 
    return $ case url of 
     Factorial n -> [X.TextNode . T.pack . show $ product [1 .. n]] 
     _ -> [] 

या यह एक सा सामान्यीकरण करने के लिए, आप ऐसा कर सकता है < फैक्टोरियलएआरजी > टैग से बांधें और अपने टेम्पलेट में निम्न कार्य करें। https://github.com/aslatter/blog/blob/master/Blog/Templates.hs इस उदाहरण में, 'appTemplates:

<p>The factorial of <factorialArg> is <factorial><factorialArg/></factorial>.</p> 
+0

मैं यहाँ पर स्नैप' rendWithSplices 'पर कस्टम happstack रूपों का उपयोग किया है 'ऐप टेम्पलेटस्टेट' टाइप करने के लिए 'फ़ंक्शन'। –

संबंधित मुद्दे