2014-09-08 5 views
6

리더 모나드 사용하는 하스켈 기능 리팩토링 :내가 내 질문에 관련이없는 모든 코드를 무시하고, 종류의이 같은 보이는 몇 가지 코드있어

import qualified Control.Monad.Reader as Reader 

data FooEnv = FooEnv { bar :: Int -> Int } 
type FooReader = Reader.Reader FooEnv 

foo :: Int -> FooReader String 
foo i = Reader.liftM show $ bar' i 
    where 
    bar' i' = do 
     bar'' <- Reader.asks bar 
     return $ bar'' i' 

것은 거기 이것을 리펙토링하는 방법? 특히 중첩 된 bar' 함수는 나를 가장 괴롭 히고 있습니다. 이것이 한 줄로 압축 될 수 있습니까?

답변

9

우리는 약간의 동등한 추론을 할 수 있습니다. 먼저 bar'을 봅시다. 나는 그것은 liftM가 위의 패턴에 맞는 liftM f m = m >>= \a -> return (f a)으로 정의되는 것으로 나타났다

asks bar >>= \z -> return (z i) 

이 양식을 작성할 수 있습니다. 그래서 우리는 liftM 우리가 인식 할 수 fmap 것을 알고있는 경우의 조금 특히

liftM show . liftM ($ i) $ asks bar 

을 작성,

liftM show (liftM ($ i) (asks bar)) 

인 또는

liftM ($ i) (asks bar) 

그런 다음 우리가 foo이로 교체하자 Functor 법칙은 여기에서

fmap show . fmap ($ i) $ asks bar -- equals 
fmap (show . ($ i)) $ asks bar 

나는 우리가 전화 사이트에서 bar를 사용하여 asks을 제거하는 결정할 수, 개인적으로 함수로 ($ i)를 사용의 큰 팬이 아니에요, 그래서

fmap (\f -> show (f i)) (asks bar) 

이제 명시 적 람다로 다시 보자 (즉 유형의 기능

fmap (\f -> show (bar f i)) ask 

및 최종 트릭으로, 우리는 fmap 치우는 기능에 무의미 가고, 심지어 asks의 사용을 반환 flip를 사용할 수 bar :: FooEnv -> Int -> Int (감사 Ørjan 요한센)

fmap (show . flip bar i) ask -- or even 
show . flip bar i <$> ask  -- or even 
asks (show . flip bar i) 
으로 bar 사용

이 작업을 수행하는 데 가장 읽기 쉽거나 멋진 방법은 아니지만, 방정식을 사용하여 어떻게 조각을 왜곡 할 수 있는지 확인할 수 있습니다.

+2

'asks f'는'f <$> ask '와 동일하므로, 여러분의 취향에 따라 다르므로 끝 부분에 다시 넣을 수 있습니다 :'asks $ show. 플립 바 i' –

+0

감사합니다, @ j-abrahamson! 자세한 단계는 매우 유용합니다. 그래도 나는 더 구체적인 것은 틀림없이, 'bar'를'foo'로 인라인하지 않으려 고합니다. 나는 당신이 취한 조치를 이해하려고 노력할 것이고, 그래서 나는 자신이 point-free 버전의 bar를 만들 수 있도록 노력할 것이다. 저는'묻기 '를 원합니다. @ Ørjan-johansen, 마지막 단계를 추가해 주셔서 감사합니다. – arussell84

+0

나는 그것을 알아 냈다 :'bar 'i'= $ flip bar i'' 또는'bar '= asks를 묻는다. 플립 바' – arussell84