내가 모나드의 개념 주위에 내 머리를 정리하려고했는데 나는 다음과 같은 예를 실험했습니다 :주 및 IO 모나드
나는 텍스트의 상태를 나타내는 Editor
데이터 유형이 문서 및 그것에 작동하는 몇 가지 기능을 제공합니다.
data Editor = Editor {
lines :: [Line], -- editor contents are kept line by line
lineCount :: Int, -- holds length lines at all times
caret :: Caret -- the current caret position
-- ... some more definitions
} deriving (Show)
-- get the line at the given position (first line is at 0)
lineAt :: Editor -> Int -> Line
lineAt ed n = ls !! n
where
ls = lines ed
-- get the line that the caret is currently on
currentLine :: Editor -> Line
currentLine ed = lineAt ed $ currentY ed
-- move the caret horizontally by the specified amount of characters (can not
-- go beyond the current line)
moveHorizontally :: Editor -> Int -> Editor
moveHorizontally ed n = ed { caret = newPos }
where
Caret x y = caret ed
l = currentLine ed
mx = fromIntegral (L.length l - 1)
newX = clamp 0 mx (x+n)
newPos = Caret newX y
-- ... and lots more functions to work with an Editor
이러한 모든 기능
는Editor
에 따라 행동하고, 그들 중 많은 사람들이 돌아 새로운
Editor
(caret의 이동이나 된 경우 일부 텍스트가 변경되었습니다) 그래서 나는 이것이
State
의 좋은 응용 프로그램이 될 줄 알았는데 모나드와 나는 대부분의 지금과 같이 할 수
Editor
-functions를 다시 작성했습니다 :
lineAt' :: Int -> State Editor Line
lineAt' n = state $ \ed -> (lines ed !! n, ed)
currentLine' :: State Editor Line
currentLine' = do
y <- currentY'
lineAt' y
moveHorizontally' :: Int -> State Editor()
moveHorizontally' n = do
(Caret x y) <- gets caret
l <- currentLine'
let mx = fromIntegral (L.length l - 1)
let newX = clamp 0 mx (x+n)
modify (\ed -> ed { caret = Caret newX y })
moveHorizontally' :: Int -> State Editor()
moveHorizontally' n = do
(Caret x y) <- gets caret
l <- currentLine'
let mx = fromIntegral (L.length l - 1)
let newX = clamp 0 mx (x+n)
modify (\ed -> ed { caret = Caret newX y })
그것은 나를 do
표기법에서 아주 쉽게 편집 작업을 구성 할 수 있기 때문에이 꽤 굉장합니다.
그러나 지금은 실제 응용 프로그램 내에서 사용하도록 고심하고 있습니다. IO를 수행하는 응용 프로그램에서이 코드를 Editor
으로 사용한다고 가정 해보십시오. 사용자가 키보드의 l
키를 누를 때마다 Editor
의 인스턴스를 조작하려고한다고 가정 해보십시오.
내가 Editor
인스턴스 수정하여 현재의 AppState을 수정 moveHorizontally'
을 키보드에서 읽을 IO
모나드를 사용하고 호출하는 정렬의 이벤트 루프를 보유하고있는 전체 애플리케이션 상태를 나타내는 또 다른 State
모나드를해야합니다 그것의 Editor
.
나는이 주제에 조금 읽어 봤는데, 하단에 IO와 모나드의 스택을 구축 할 모나드 트랜스 포머를 사용해야하는 것처럼 보인다. Monad Transformers는 한번도 사용 해본 적이 없으며 여기서 무엇을해야할지 모르겠습니다. 나는 또한 State
모나드가 이미 일부 기능을 구현한다는 것을 알았지 만 (모나드 변압기의 특수한 경우 인 것 같습니까?) 사용 방법에 대해 혼란 스럽습니다.
는 "이러한 모든 기능은 에디터에 따라 행동하고, 그들 중 많은 (새로운 편집기를 반환 캐럿이 이동되었거나 일부 텍스트가 변경된 곳) "- 이것은 좋은 것입니다! 원래의 순수 함수를 적용한 일반 IO 루프가 메모리에 새 편집기를 생성하는 것은 거의 없습니다.GHC는 필요한 경우에만 구조체를 복사하고 이전 참조가 사용되지 않으면 내부에서 업데이트합니다. 여기서 변압기를 반드시 사용할 필요는 없으며 코드가 없으면 코드가 더 명확 해집니다. – thumphries
@ DeX3 참고로 * 자체 포함 * 게시물을 제출하면 사람들이 귀하의 질문에 답변하기 위해 코드를 작성하는 것이 훨씬 쉬워집니다. – gallais