인덱스 된 모나드 는 무엇 이며이 모나드 의 동기 는 무엇입니까 ?
나는 그것이 부작용을 추적하는 데 도움이된다고 읽었습니다. 그러나 형식 서명과 문서는 나를 어디로도 인도하지 않습니다.
부작용 (또는 다른 유효한 예)을 추적하는 데 도움이 될 수있는 예는 무엇입니까?
답변
그 어느 때보 다 사람들이 사용하는 용어는 완전히 일치하지 않습니다. 모나드에 의해 영감을 받았지만 엄격하게 말하는 것은 그다지 중요한 개념이 다양합니다. “인덱싱 된 모나드”라는 용어는 이러한 개념을 특성화하는 데 사용되는 용어의 숫자 ( “모나드”및 “매개 변수화 된 모나드”(Atkey의 이름) 포함) 중 하나입니다. (관심이 있다면 또 다른 개념은 모노 이드로 색인 된 Katsumata의 “파라 메트릭 효과 모나드”입니다. 여기서 return은 중립적으로 색인되고 bind는 색인에 누적됩니다.)
먼저 종류를 확인합시다.
IxMonad (m :: state -> state -> * -> *)
즉, “계산”(또는 원하는 경우 “액션”이지만 “계산”을 고수하겠습니다)의 유형은 다음과 같습니다.
m before after value
어디 before, after :: state
와 value :: *
. 이 아이디어는 예측 가능한 상태 개념 을 가진 외부 시스템과 안전하게 상호 작용하는 수단을 포착하는 것입니다 . 하는 계산으로의 유형은 국가가해야 무엇을 알려줍니다 before
, 그것은 실행 상태가 될 것입니다 무엇을 after
그것을 실행하고 (정기적 인 모나드와 같은 *
어떤 종류의) value
계산이 생산의.
일반적인 비트와 조각은 *
모나드와 state
같고 도미노를 연주하는 것과 같습니다.
ireturn :: a -> m i i a -- returning a pure value preserves state
ibind :: m i j a -> -- we can go from i to j and get an a, thence
(a -> m j k b) -- we can go from j to k and get a b, therefore
-> m i k b -- we can indeed go from i to k and get a b
이렇게 생성 된 “Kleisli 화살표”(계산을 생성하는 함수)의 개념은 다음과 같습니다.
a -> m i j b -- values a in, b out; state transition i to j
그리고 우리는 구성을 얻습니다
icomp :: IxMonad m => (b -> m j k c) -> (a -> m i j b) -> a -> m i k c
icomp f g = \ a -> ibind (g a) f
와 같은 적, 법률 정확히을 확인 ireturn
하고 icomp
우리의 카테고리를 제공
ireturn `icomp` g = g
f `icomp` ireturn = f
(f `icomp` g) `icomp` h = f `icomp` (g `icomp` h)
또는 코미디 가짜 C / Java / 무엇이든
g(); skip = g()
skip; f() = f()
{g(); h()}; f() = h(); {g(); f()}
왜 귀찮게? 상호 작용의 “규칙”을 모델링합니다. 예를 들어, 드라이브에 DVD가 없으면 DVD를 꺼낼 수없고 DVD가 이미있는 경우 드라이브에 DVD를 넣을 수 없습니다. 그래서
data DVDDrive :: Bool -> Bool -> * -> * where -- Bool is "drive full?"
DReturn :: a -> DVDDrive i i a
DInsert :: DVD -> -- you have a DVD
DVDDrive True k a -> -- you know how to continue full
DVDDrive False k a -- so you can insert from empty
DEject :: (DVD -> -- once you receive a DVD
DVDDrive False k a) -> -- you know how to continue empty
DVDDrive True k a -- so you can eject when full
instance IxMonad DVDDrive where -- put these methods where they need to go
ireturn = DReturn -- so this goes somewhere else
ibind (DReturn a) k = k a
ibind (DInsert dvd j) k = DInsert dvd (ibind j k)
ibind (DEject j) k = DEject j $ \ dvd -> ibind (j dvd) k
이를 통해 “기본”명령을 정의 할 수 있습니다.
dInsert :: DVD -> DVDDrive False True ()
dInsert dvd = DInsert dvd $ DReturn ()
dEject :: DVDrive True False DVD
dEject = DEject $ \ dvd -> DReturn dvd
다른 사람들이 ireturn
및 ibind
. 이제 쓸 수 있습니다. (차용- do
표기법)
discSwap :: DVD -> DVDDrive True True DVD
discSwap dvd = do dvd' <- dEject; dInsert dvd ; ireturn dvd'
그러나 물리적으로 불가능한 것은 아닙니다
discSwap :: DVD -> DVDDrive True True DVD
discSwap dvd = do dInsert dvd; dEject -- ouch!
또는 기본 명령을 직접 정의 할 수 있습니다.
data DVDCommand :: Bool -> Bool -> * -> * where
InsertC :: DVD -> DVDCommand False True ()
EjectC :: DVDCommand True False DVD
그런 다음 일반 템플릿을 인스턴스화합니다.
data CommandIxMonad :: (state -> state -> * -> *) ->
state -> state -> * -> * where
CReturn :: a -> CommandIxMonad c i i a
(:?) :: c i j a -> (a -> CommandIxMonad c j k b) ->
CommandIxMonad c i k b
instance IxMonad (CommandIxMonad c) where
ireturn = CReturn
ibind (CReturn a) k = k a
ibind (c :? j) k = c :? \ a -> ibind (j a) k
실제로, 우리는 원시 Kleisli 화살이 무엇인지 (하나의 “도미노”가 무엇인지) 말한 다음 그 위에 “계산 시퀀스”라는 적절한 개념을 구축했습니다.
인덱스 된 모든 모나드 m
에 대해 “대각선 변경 없음” m i i
은 모나드이지만 일반적으로m i j
으로 그렇지 않습니다. 또한 값은 색인화되지 않지만 계산은 색인화되므로 색인화 된 모나드는 다른 범주에 대해 인스턴스화 된 모나드의 일반적인 아이디어가 아닙니다.
자, Kleisli 화살의 종류를 다시보세요
a -> m i j b
우리는 i
시작 하려면 상태 에 있어야한다는 것을 알고 있으며 모든 지속은 상태에서 시작될 것이라고 예측합니다 j
. 우리는이 시스템에 대해 많이 알고 있습니다! 이것은 위험한 작업이 아닙니다! DVD를 드라이브에 넣으면 들어갑니다! DVD 드라이브는 각 명령 이후의 상태에 대해 어떠한 말도하지 않습니다.
그러나 그것은 일반적으로 세상과 상호 작용할 때 사실이 아닙니다. 때로는 통제권을 포기하고 세상이 좋아하는 일을하도록해야 할 수도 있습니다. 예를 들어, 서버 인 경우 클라이언트에게 선택권을 제공 할 수 있으며 세션 상태는 선택하는 항목에 따라 달라집니다. 서버의 “제공 선택”작업은 결과 상태를 결정하지 않지만 서버는 어쨌든 계속할 수 있어야합니다. 위의 의미에서 “기본 명령”이 아니므로 인덱스 된 모나드는 예측할 수없는 것을 모델링하는 좋은 도구가 아닙니다. 시나리오 .
더 나은 도구는 무엇입니까?
type f :-> g = forall state. f state -> g state
class MonadIx (m :: (state -> *) -> (state -> *)) where
returnIx :: x :-> m x
flipBindIx :: (a :-> m b) -> (m a :-> m b) -- tidier than bindIx
무서운 비스킷? 두 가지 이유가 있습니다. 이 때문에 하나, 그것은, 모나드가 무엇인지와 같은 오히려 더 보이는 것입니다 이상 모나드 만 (state -> *)
이 아니라 *
. 둘째, Kleisli 화살의 종류를 보면
a :-> m b = forall state. a state -> m b state
Good Old Hoare Logic에서 와 같이 전제 조건 a
및 후 조건 으로 계산 유형을 얻습니다 b
. 프로그램 논리에 대한 주장은 Curry-Howard 서신을 통과하고 Haskell 유형이되는 데 반세기 미만이 걸렸습니다. returnIx
“건너 뛰기”에 대한 Hoare Logic 규칙 인 “아무것도하지 않고 유지되는 모든 사후 조건을 달성 할 수 있습니다.” 라는 유형입니다 . 해당 구성은 “;”에 대한 Hoare Logic 규칙입니다.
유형을 살펴보고 bindIx
모든 수량자를 입력하여 마무리하겠습니다 .
bindIx :: forall i. m a i -> (forall j. a j -> m b j) -> m b i
이것들 forall
은 반대 극성을 가지고 있습니다. 우리는 초기 상태 와 사후 조건으로 i
시작할 수있는 계산을 선택합니다 . 세상은 자신이 좋아 하는 중간 상태를 선택 하지만 사후 조건이 유지 된다는 증거를 우리에게 제공해야하며 그러한 상태에서 우리는 계속 유지할 수 있습니다. 따라서 순서대로 state에서 조건 을 얻을 수 있습니다 . “이후”상태에 대한 그립을 해제함으로써 예측할 수없는 계산을 모델링 할 수 있습니다 .i
a
j
b
b
b
i
모두 IxMonad
와 MonadIx
유용합니다. 두 모델 모두 상태 변화, 예측 가능 및 예측 불가능과 관련하여 상호 작용 계산의 유효성을 모델링합니다. 예측 가능성은 얻을 수있을 때 가치가 있지만 예측 불가능 성은 때때로 삶의 사실입니다. 바라건대,이 답변은 인덱스 모나드가 무엇인지에 대한 일부 표시를 제공하여 유용하기 시작하는시기와 중지되는시기를 모두 예측합니다.
답변
내가 아는 인덱스 모나드를 정의하는 방법은 최소한 세 가지가 있습니다.
나는 이러한 옵션을 색인 된 모나드 à la X 라고 부르겠습니다. X는 컴퓨터 과학자 인 Bob Atkey, Conor McBride 및 Dominic Orchard에 걸쳐 있습니다. 이 구성의 일부는 범주 이론을 통해 훨씬 더 긴 저명한 역사와 더 좋은 해석을 가지고 있지만 처음에는 이러한 이름과 관련된 것을 배웠고이 대답이 너무 난해 하지 않도록 노력하고 있습니다.
Atkey
Bob Atkey의 인덱스 된 모나드 스타일은 모나드의 인덱스를 처리하기 위해 2 개의 추가 매개 변수로 작업하는 것입니다.
이를 통해 사람들이 다른 답변에서 던진 정의를 얻을 수 있습니다.
class IMonad m where
ireturn :: a -> m i i a
ibind :: m i j a -> (a -> m j k b) -> m i k b
또한 Atkey의 색인화 된 comonads를 정의 할 수 있습니다. 나는 실제로 코드베이스 에서lens
많은 마일리지를 얻습니다 .
McBride
색인화 된 모나드의 다음 형태는 Conor McBride가 그의 논문 “Outrageous Fortune의 Kleisli Arrows” 에서 정의한 것 입니다. 대신 색인에 단일 매개 변수를 사용합니다. 이것은 인덱스 된 모나드 정의가 다소 영리한 형태를 갖도록합니다.
다음과 같이 매개 변수를 사용하여 자연 변환을 정의하면
type a ~> b = forall i. a i -> b i
McBride의 정의를 다음과 같이 작성할 수 있습니다.
class IMonad m where
ireturn :: a ~> m a
ibind :: (a ~> m b) -> (m a ~> m b)
이것은 Atkey와는 상당히 다른 느낌이 들지만 모나드를 구축하는 대신 일반 모나드와 비슷하게 느껴 (m :: * -> *)
집니다 (m :: (k -> *) -> (k -> *)
.
흥미롭게도 McBride는 그의 모방 할 수없는 스타일의 McBride가 “at key”로 읽어야한다고 선택하는 영리한 데이터 유형을 사용하여 McBride에서 색인화 된 모나드의 Atkey 스타일을 실제로 복구 할 수 있습니다.
data (:=) :: a i j where
V :: a -> (a := i) i
이제 당신은 그것을 해결할 수 있습니다
ireturn :: IMonad m => (a := j) ~> m (a := j)
확장되는
ireturn :: IMonad m => (a := j) i -> m (a := j) i
j = i 일 때만 호출 할 수 있으며,을주의 깊게 읽으면 ibind
Atkey의 ibind
. 이러한 (: =) 데이터 구조를 전달해야하지만 Atkey 프레젠테이션의 힘을 회복합니다.
반면에 Atkey 프레젠테이션은 McBride 버전의 모든 사용을 복구 할만큼 강력하지 않습니다. 권력은 엄격하게 획득되었습니다.
또 다른 좋은 점은 McBride의 인덱스 된 모나드는 분명히 모나드라는 것입니다. 다른 펑터 범주의 모나드 일뿐입니다. 그것은 펑터의 범주 (k -> *)
가 (k -> *)
아닌 펑터의 범주에있는 endofunctor에 대해 작동 *
합니다 *
.
재미있는 연습은 색인 된 코 모나드에 대해 McBride에서 Atkey로 변환하는 방법을 알아내는 것 입니다. 개인적으로 McBride의 논문에서 “at key”구성에 데이터 유형 ‘At’을 사용합니다. 저는 실제로 ICFP 2013에서 Bob Atkey에게 다가 가서 그를 뒤집어 “코트”로 만들었다 고 말했습니다. 그는 눈에 띄게 혼란스러워 보였다. 내 머릿속에서 라인이 더 잘 연주되었습니다. =)
과수원
마지막으로, “인덱싱 된 모나드”라는 이름에 대해 거의 드물게 참조되는 세 번째 주장자는 Dominic Orchard에 기인합니다. 대신 그는 유형 수준의 모노 이드를 사용하여 인덱스를 합칩니다. 구성에 대한 세부 사항을 살펴보기보다는 간단히이 강연에 연결하겠습니다.
https://github.com/dorchard/effect-monad/blob/master/docs/ixmonad-fita14.pdf
답변
간단한 시나리오로 상태 모나드가 있다고 가정합니다. 상태 유형은 복잡한 대형 유형이지만 이러한 모든 상태는 빨간색과 파란색 상태의 두 세트로 분할 될 수 있습니다. 이 모나드의 일부 작업은 현재 상태가 파란색 상태 인 경우에만 의미가 있습니다. 이 중 일부는 상태를 파란색 ( blueToBlue
)으로 유지하고 다른 일부는 상태를 빨간색 ( blueToRed
)으로 유지합니다. 일반 모나드에서는 다음과 같이 작성할 수 있습니다.
blueToRed :: State S ()
blueToBlue :: State S ()
foo :: State S ()
foo = do blueToRed
blueToBlue
두 번째 작업이 파란색 상태를 예상하기 때문에 런타임 오류를 트리거합니다. 이것을 정적으로 방지하고 싶습니다. 인덱싱 된 모나드는이 목표를 달성합니다.
data Red
data Blue
-- assume a new indexed State monad
blueToRed :: State S Blue Red ()
blueToBlue :: State S Blue Blue ()
foo :: State S ?? ?? ()
foo = blueToRed `ibind` \_ ->
blueToBlue -- type error
두 번째 인덱스 인해 입력 오류 트리거 blueToRed
( Red
)의 첫번째 인덱스 다르다 blueToBlue
( Blue
).
또 다른 예로, 인덱스 된 모나드를 사용하면 상태 모나드가 상태에 대한 유형을 변경할 수 있습니다.
data State old new a = State (old -> (new, a))
위를 사용하여 정적으로 유형이 지정된 이기종 스택 인 상태를 빌드 할 수 있습니다. 작업에는 유형이 있습니다.
push :: a -> State old (a,old) ()
pop :: State (a,new) new a
또 다른 예로, 파일 액세스를 허용하지 않는 제한된 IO 모나드가 필요하다고 가정합니다. 예를 들어 사용할 수 있습니다.
openFile :: IO any FilesAccessed ()
newIORef :: a -> IO any any (IORef a)
-- no operation of type :: IO any NoAccess _
이런 식 IO ... NoAccess ()
으로 유형 이 있는 작업 은 정적으로 파일 액세스가 없음을 보장합니다. 대신 작업 유형 IO ... FilesAccessed ()
이 파일에 액세스 할 수 있습니다. 인덱싱 된 모나드가 있다는 것은 제한된 IO에 대해 별도의 유형을 빌드 할 필요가 없음을 의미하며, 두 IO 유형 모두에서 파일과 관련이없는 모든 함수를 복제해야합니다.
답변
인덱싱 된 모나드는 예를 들어 상태 모나드와 같은 특정 모나드가 아니라 추가 유형 매개 변수가있는 모나드 개념의 일종의 일반화입니다.
“표준”모나드 값이 유형을 Monad m => m a
갖는 반면, 인덱스 모나드의 값은 IndexedMonad m => m i j a
어디에 i
있고 j
인덱스 유형이므로 i
모나드 계산 시작과 계산 j
끝의 인덱스 유형이 됩니다. 어떤 의미에서는 i
일종의 입력 유형과 j
출력 유형으로 생각할 수 있습니다 .
사용 State
예로서, 상태 연산은 State s a
입력의 상태를 유지 s
연산 통하여 입력의 결과를 반환한다 a
. 인덱싱 된 버전 IndexedState i j a
은 계산 중에 상태가 다른 유형으로 변경 될 수있는 상태 저장 계산입니다. 초기 상태에는 유형 i
과 상태가 있고 계산의 끝에는 유형이 j
있습니다.
인덱싱 된 모나드를 일반 모나드에 사용하는 것은 거의 필요하지 않지만 경우에 따라 더 엄격한 정적 보장을 인코딩하는 데 사용할 수 있습니다.
답변
종속 유형 (예 : agda)에서 인덱싱이 어떻게 사용되는지 살펴 보는 것이 중요 할 수 있습니다. 이것은 인덱싱이 일반적으로 어떻게 도움이되는지 설명 할 수 있으며이 경험을 모나드로 변환 할 수 있습니다.
인덱싱을 사용하면 특정 유형 인스턴스 간의 관계를 설정할 수 있습니다. 그런 다음 그 관계가 유지되는지 확인하기 위해 몇 가지 값에 대해 추론 할 수 있습니다.
예를 들어 (agda에서) 일부 자연수가와 관련이 있음을 지정할 수 _<_
있으며 유형은 어떤 숫자인지 알려줍니다. 그런 다음 일부 함수에 m < n
.
또 다른 예로, 선택한 언어에 대한 충분한 인내와 컴파일러 지원이 주어지면 함수가 특정 목록이 정렬 된 것으로 가정하도록 인코딩 할 수 있습니다.
인덱싱 된 모나드는 부작용을보다 정확하게 관리하기 위해 종속 형 시스템이 수행하는 작업 중 일부를 인코딩 할 수 있습니다.