하스켈에서 Control.Monad.Writer를 사용하는 방법?
저는 함수형 프로그래밍을 처음 접했고 최근에는 Learn You a Haskell 에서 배웠지 만이 장을 살펴 보았을 때 아래 프로그램을 고수했습니다.
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
이 줄을 .hs 파일에 저장했지만 불평 한 내 ghci로 가져 오지 못했습니다.
more1.hs:4:15:
Not in scope: data constructor `Writer'
Perhaps you meant `WriterT' (imported from Control.Monad.Writer)
Failed, modules loaded: none.
": info"명령으로 유형을 조사했습니다.
Prelude Control.Monad.Writer> :info Writer
type Writer w = WriterT w Data.Functor.Identity.Identity
-- Defined in `Control.Monad.Trans.Writer.Lazy'
내 관점에서 이것은 "newtype Writer wa ..."와 같은 것으로되어 있었기 때문에 데이터 생성자를 공급하고 Writer를 얻는 방법에 대해 혼란 스럽습니다.
버전 관련 문제 일 수 있으며 ghci 버전은 7.4.1입니다.
패키지 Control.Monad.Writer
는 데이터 생성자를 내 보내지 않습니다 Writer
. LYAH가 쓰여졌을 때 이것이 달랐던 것 같아요.
ghci에서 MonadWriter 유형 클래스 사용
대신 writer
함수를 사용하여 작성자를 만듭니다 . 예를 들어, ghci 세션에서
ghci> import Control.Monad.Writer
ghci> let logNumber x = writer (x, ["Got number: " ++ show x])
이제 logNumber
작가를 만드는 함수입니다. 유형을 요청할 수 있습니다.
ghci> :t logNumber
logNumber :: (Show a, MonadWriter [String] m) => a -> m a
이것은 추론 된 유형이 특정 작성자 를 반환하는 함수가 아니라 MonadWriter
유형 클래스 를 구현하는 모든 것을 의미합니다 . 이제 사용할 수 있습니다.
ghci> let multWithLog = do { a <- logNumber 3; b <- logNumber 5; return (a*b) }
:: Writer [String] Int
(실제로 한 줄에 모두 입력 된 입력). 여기에서 유형을 multWithLog
로 지정했습니다 Writer [String] Int
. 이제 실행할 수 있습니다.
ghci> runWriter multWithLog
(15, ["Got number: 3","Got number: 5"])
그리고 모든 중간 작업을 기록하는 것을 볼 수 있습니다.
코드가 이렇게 작성된 이유는 무엇입니까?
MonadWriter
유형 클래스 를 생성해야하는 이유는 무엇 입니까? 그 이유는 모나드 변환기와 관련이 있습니다. 올바르게 인식했듯이 구현하는 가장 간단한 방법 Writer
은 쌍 위에 새로운 유형 래퍼를 사용하는 것입니다.
newtype Writer w a = Writer { runWriter :: (a,w) }
You can declare a monad instance for this, and then write the function
tell :: Monoid w => w -> Writer w ()
which simply logs its input. Now suppose you want a monad that has logging capabilities, but also does something else - say it can read from an environment too. You'd implement this as
type RW r w a = ReaderT r (Writer w a)
Now because the writer is inside the ReaderT
monad transformer, if you want to log output you can't use tell w
(because that only operates with unwrapped writers) but you have to use lift $ tell w
, which "lifts" the tell
function through the ReaderT
so that it can access the inner writer monad. If you wanted two layers transformers (say you wanted to add error handling as well) then you'd need to use lift $ lift $ tell w
. This quickly gets unwieldy.
Instead, by defining a type class we can make any monad transformer wrapper around a writer into an instance of writer itself. For example,
instance (Monoid w, MonadWriter w m) => MonadWriter w (ReaderT r m)
that is, if w
is a monoid, and m
is a MonadWriter w
, then ReaderT r m
is also a MonadWriter w
. This means that we can use the tell
function directly on the transformed monad, without having to bother with explicitly lifting it through the monad transformer.
A function called "writer" is made available in lieu of a "Writer" constructor. Change:
logNumber x = Writer (x, ["Got number: " ++ show x])
to:
logNumber x = writer (x, ["Got number: " ++ show x])
I got a similar message from trying the LYAH "For a few Monads More" using the online Haskell editor in repl.it
I changed the import from:
import Control.Monad.Writer
to:
import qualified Control.Monad.Trans.Writer.Lazy as W
So my code now works looking like this (with inspiration from Kwang's Haskell Blog):
import Data.Monoid
import qualified Control.Monad.Trans.Writer.Lazy as W
output :: String -> W.Writer [String] ()
output x = W.tell [x]
gcd' :: Int -> Int -> W.Writer [String] Int
gcd' a b
| b == 0 = do
output ("Finished with " ++ show a)
return a
| otherwise = do
output (show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b))
gcd' b (a `mod` b)
main :: IO()
main = mapM_ putStrLn $ snd $ W.runWriter (gcd' 8 3)
Code is currently runable here
참고URL : https://stackoverflow.com/questions/11684321/how-to-play-with-control-monad-writer-in-haskell
'Programing' 카테고리의 다른 글
Unity의 Resolve () 메서드에 생성자 매개 변수를 전달할 수 있습니까? (0) | 2020.09.14 |
---|---|
콘솔 모드에서 Emacs의 메뉴에 어떻게 가나 요? (0) | 2020.09.14 |
git 태그 (또는이를 기반으로 한 GitHub 릴리스)의 날짜 변경 (0) | 2020.09.14 |
하나의 .R 파일에 모든 함수를 정의하고 다른 .R 파일에서 호출합니다. (0) | 2020.09.14 |
POSIX 파일 설명자에서 C ++ fstream을 구성하는 방법은 무엇입니까? (0) | 2020.09.14 |