2012-05-11 4 views
3

취미 웹 프로젝트가 있습니다. 아주 간단 하스켈과 웹 프로그래밍을 배우기 만하면됩니다. 명확성을 위해 Snap 프레임 워크를 사용합니다.다른 모나드 아래의 상태 코드

auth :: MonadSnap m => m ByteString 
auth = withSession $ \s -> do 
    Just user <- getPostParam "user" 
    Just password <- getPostParam "password" 
    if user == "demi" && password == "1234" 
     then redirect "/" 
     else redirect "/login" 

withSession는 현재 세션을 읽고 매개 변수 기능을 실행 : 그리고 다음 코드 (site.com/auth 핸들러)가 있습니다. 여기에 나는 문제가있다 : 사용자가 승인을 받고 새로운 값을 세션 s에 넣고 코드를 실행하고 싶다. 가장 좋은 방법은 무엇입니까? 어떻게 할거 니? 아래 코드에서도 s을 사용한다고 가정합니다.

또 다른 질문 : 어떻게 든 컨텍스트를 처리기 (예 : auth)와 다른 기능에서 투명하게 사용할 수 있습니까?

findGoodies :: MonadSnap m => MyContext -> String -> m String 
checkCaptcha :: MonadSnap m => MyContext -> m Bool 
breakingNews :: MonadSnap m => MyContext -> m ByteString 

가 이상적으로, 내가하는 기능 withContext를 갖고 싶어하지만, 문맥 중에 변경 될 수 있습니다 : 나는 ctx 같은 매개 변수를 사용하여 모든 기능에서 (DB 연결, 세션 및 아마 다른처럼) 모든 상황을 끌어 싶지 않아 요청을 처리합니다. 내 모나드를 정의하는 문제를 해결할 수 있다고 생각 하나 (맞습니까?),하지만 Snap Monad를 사용해야하고 확장 할 수 없습니다 (이것은 역시 문제입니다).

희망 나는 그것을 도와주기 위해 꽤 분명하게 말한다.

+0

어떻게 'withSession'이 현재 세션을 읽습니까? 'MonadSnap' 인스턴스'm'이 세션에 대한 접근을 제공하면,'m' 모나드에서 값을 반환하는 모든 함수 또한 같은 방법으로 세션에 접근해야합니다. – pat

+0

이것은 내 손으로 만든 세션입니다. 그 이름으로 서버에 쿠키와 파일로 구현되었습니다. :) 웹의 내부를 만지고 싶기 때문에 세션 관리를위한 스냅 하위 시스템을 설치하지 않았습니다. – demi

+0

Pat의 StateT에 대한 답은 맞습니다. 바로 이것이 우리가 snaplet과 Handler 모나드를 만든 이유입니다. 핸들러는 사실상 두포 상태의 StateT입니다. 그것은 당신을 위해 모든 세부 사항을 처리합니다. 시작하려면 [snaplets tutorial] (http://snapframework.com/docs/tutorials/snaplets-tutorial)을 확인하십시오. – mightybyte

답변

4

컨텍스트가 상태 인 StateTMonadSnap 모나드를 래핑 할 수 있습니다. 적절한 인스턴스가 정의되면 세션 상태에 액세스 할 수 있지만 lift 없이도 MonadSnap 함수를 호출 할 수있는 함수를 새 모나드에 작성할 수 있습니다.

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
import Control.Monad.State 

-- StateT wrapper 
newtype MySnapT m a = MySnapT { unMySnapT :: StateT MyContext m a } 
    deriving (Monad) 

instance MonadTrans MySnapT where 
    lift = MySnapT . lift 

instance MonadSnap m => MonadSnap (MySnapT m) where 
    liftSnap = lift . liftSnap 

instance MonadSnap m => MonadState MyContext (MySnapT m) where 
    get = MySnapT get 
    put = MySnapT . put 

runMySnapT :: MonadSnap m => MySnapT m a -> MyContext -> m (a, MyContext) 
runMySnapT m = runStateT . unMySnapT $ m 

-- wrapper for withSession that runs a MySnapT action with 
-- the current session as the StateT state, and sets the 
-- resulting state back when it is done 
withMySession :: MonadSnap m => MySnapT m a -> m a 
withMySession m = do 
    (a, s') <- withSession $ runMySnapT m -- read the session and run the action 
    setSession s' -- write the session back to disk 
    return a   



-- functions that run in the MySnapT monad have access to context as 
-- state, but can still call MonadSnap functions 
findGoodies :: MonadSnap m => String -> MySnapT m String 
findGoodies s = do 
    s <- get -- get the session 
    put $ modifySession s -- modify and set the session back into the State 
    liftSnap undefined -- I can still call Snap functions 
    return "Hello" 

auth :: MonadSnap m => m String 
auth = withMySession $ do -- use withMySession to run MySnapT actions 
    findGoodies "foo" 


-- dummy definitions for stuff I don't have 

data Snap a = Snap a 

class Monad m => MonadSnap m where 
    liftSnap :: Snap a -> m a 

data MyContext = MyContext 

withSession :: MonadSnap m => (MyContext -> m a) -> m a 
withSession = undefined 

setSession :: MonadSnap m => MyContext -> m() 
setSession = undefined 

modifySession :: MyContext -> MyContext 
modifySession = undefined 
관련 문제