무료 모나드는 무엇입니까?


368

나는 용어를 본 적이 무료 모나드가 팝업 모든 현재 다음 몇 시간 동안, 그러나 모두는 / 사용 그들이 무엇인지에 대한 설명을 제공하지 않고 그것들을 논의 할 것으로 보인다. 무료 모나드는 무엇입니까? (저는 모나드와 하스켈 기본에 익숙하지만 범주 이론에 대한 지식은 매우 큽니다.)


12
상당히 좋은 설명이 여기있다 haskellforall.com/2012/06/…
Roger

19
@Roger 그것은 나를 여기로 데려온 일종의 페이지입니다. 저에게이 예제는 "Free"라는 유형에 대한 모나드 인스턴스를 정의합니다.
David

답변:


295

Edward Kmett의 대답은 분명히 훌륭합니다. 그러나 약간 기술적 인 부분입니다. 여기 좀 더 접근하기 쉬운 설명이 있습니다.

무료 모나드는 펑터를 모나드로 바꾸는 일반적인 방법 일뿐입니다. 즉, 어떤 functor f Free f도 monad입니다. 함수 쌍을 얻는 것을 제외하고는 매우 유용하지 않습니다.

liftFree :: Functor f => f a -> Free f a
foldFree :: Functor f => (f r -> r) -> Free f r -> r

이 중 첫 번째는 모나드에 "들어가"고 두 번째는 모나드에서 "나가"는 방법을 제공합니다.

보다 일반적으로, X가 여분의 물건 P를 가진 Y 인 경우, "자유로운 X"는 추가적인 것을 얻지 않고 Y에서 X로가는 방법입니다.

예 : monoid (X)는 기본적으로 추가 (생각을 생각할 수 있음) 및 일부 동일성 (0과 같은)이 있다고하는 추가 구조 (P)가있는 집합 (Y)입니다.

그래서

class Monoid m where
   mempty  :: m
   mappend :: m -> m -> m

자, 우리 모두리스트를 알고 있습니다

data [a] = [] | a : [a]

음, 어떤 종류의 주어진 t우리가 알고 [t]모노 이드 인을

instance Monoid [t] where
  mempty   = []
  mappend = (++)

따라서 목록은 세트 (또는 하스켈 유형)에 대한 "자유 모노 이드"입니다.

무료 모나드는 같은 생각입니다. 우리는 functor를 가지고 모나드를 돌려줍니다. 실제로 모나드는 endofunctors 범주에서 monoid로 볼 수 있으므로 목록의 정의

data [a] = [] | a : [a]

무료 모나드의 정의와 매우 비슷합니다.

data Free f a = Pure a | Roll (f (Free f a))

그리고 Monad인스턴스에 유사성이 Monoid목록에 대한 인스턴스를

--it needs to be a functor
instance Functor f => Functor (Free f) where
  fmap f (Pure a) = Pure (f a)
  fmap f (Roll x) = Roll (fmap (fmap f) x)

--this is the same thing as (++) basically
concatFree :: Functor f => Free f (Free f a) -> Free f a
concatFree (Pure x) = x
concatFree (Roll y) = Roll (fmap concatFree y)

instance Functor f => Monad (Free f) where
  return = Pure -- just like []
  x >>= f = concatFree (fmap f x)  --this is the standard concatMap definition of bind

이제 두 가지 작업을 수행합니다

-- this is essentially the same as \x -> [x]
liftFree :: Functor f => f a -> Free f a
liftFree x = Roll (fmap Pure x)

-- this is essentially the same as folding a list
foldFree :: Functor f => (f r -> r) -> Free f r -> r
foldFree _ (Pure a) = a
foldFree f (Roll x) = f (fmap (foldFree f) x)

12
이것은 내가 본 "무료"에 대한 가장 접근하기 쉬운 설명 일 수 있습니다. 특히 "더 일반적으로"로 시작하는 단락.
John L

16
"f는 여러 번 적용됨" Free f a = Pure a | Roll (f (Free f a))으로 보는 것이 재미 있다고 생각합니다 Free f a = a + fa + ffa + .... 그런 다음 concatFree(즉, join)는 "f를 여러 번 적용 (f를 여러 번 적용)"하여 두 개의 중첩 된 응용 프로그램을 하나로 축소합니다. 그리고 >>="f는 a에 여러 번 적용"과 "a에서 b를 얻는 방법 (f는 여러 번 적용됨)"이 필요하며 기본적으로 후자를 전자 내부의 a에 적용하고 중첩을 축소합니다. 지금 나는 그것을 얻는다!
jkff 1

1
이다 concatFree기본적으로 join?
rgrinberg

11
“여기에 더 접근하기 쉬운 설명이 있습니다. […] 사실, 모나드는 엔도 펑터 범주에서 단일체로 볼 수 있기 때문에…”그럼에도 불구하고, 이것은 매우 좋은 대답이라고 생각합니다.
Ruud

2
<3가 (당신이 연결해야 "모나드는 엔도 펑터의 범주에 monoids으로 볼 수있다" stackoverflow.com/a/3870310/1306877 모든 haskeller 그 기준에 대해 알고 있어야하기 때문에!)
TLO

418

더 간단한 대답은 다음과 같습니다. Monad는 수도원 컨텍스트가 축소 될 때 "계산되는"것입니다 join :: m (m a) -> m a(호출을 >>=로 정의 할 수 있음 x >>= y = join (fmap y x)). 이것은 일련의 계산 체인을 통해 Monads가 컨텍스트를 전달하는 방법입니다. 시리즈의 각 지점에서 이전 호출의 컨텍스트가 다음 호출로 축소되기 때문입니다.

무료 모나드 모두 만족 모나드 법률은, 그러나 어떤 붕괴 (즉, 계산)을하지 않습니다. 중첩 된 일련의 컨텍스트를 작성합니다. 이러한 자유 모나 딕 값을 생성하는 사용자는 이러한 중첩 된 컨텍스트로 무언가를 수행해야하므로 모나드 값이 생성 될 때까지 그러한 구성 의 의미 를 연기 할 수 있습니다.


8
귀하의 단락은 필립의 게시물에 정말 큰 도움이됩니다.
David

20
나는이 답변을 정말로 좋아한다.
danidiaz

5
무료 모나드는 Monad 타입 클래스를 대체 할 수 있습니까? 즉, free monad의 return and bind 만 사용하여 프로그램을 작성한 다음 Mwybe 또는 List 또는 원하는 것을 사용하여 결과를 결합하거나 하나의 바인드 / 연결된 함수 호출 시퀀스의 여러 모나드보기를 생성 할 수 있습니까? 즉 바닥과 비 종료를 무시합니다.
misterbee

2
이 답변은 도움이되었지만 NICTA 과정에서 '가입'을하지 않고 haskellforall.com/2012/06/…을 읽으면 혼란 스러울 것 입니다. 따라서 이해하기위한 속임수는 잠들 때까지 많은 답변을 읽는 것입니다. (NICTA 참조 : github.com/NICTA/course/blob/master/src/Course/Bind.hs )
Martin Capodici

1
이 답변은 최고입니다
Curycu

142

무료 foo는 모든 'foo'법을 만족시키는 가장 간단한 것입니다. 다시 말해, 그것은 foo가되기 위해 필요한 법칙을 완벽하게 충족 시키며 추가적인 것은 아닙니다.

잊혀진 functor는 한 범주에서 다른 범주로 갈 때 구조의 일부를 "잊어 버린"것입니다.

주어 펑 F : D -> C, 그리고 G : C -> D, 우리 말 F -| G, F수반 행렬을하기 위해 남아있는 G, 또는 G에서 오른쪽으로 수반 행렬이다 FFORALL A는, B는 때마다 : F a -> b에 동형 a -> G b화살표 적절한 범주 어디에서 왔는지.

공식적으로, 무료 functor는 잊혀진 functor에 인접 해 있습니다.

무료 모노 이드

더 간단한 예인 무료 모노 이드로 시작하겠습니다.

일부 이동 통신사 집합 T, 한 쌍의 요소를 함께 묶는 이진 함수 f :: T → T → T, 및 unit :: T연관 법칙 및 신원 법칙을 갖도록 정의 된 monoid를 사용하십시오 f(unit,x) = x = f(x,unit).

당신은 펑터를 할 수 있습니다 U(그들이지도 확인 화살표입니다, 모노 이드 homomorphisms 곳 monoids의 범주에서 unitunit다른 모노 이드에, 당신은 의미를 변경하지 않고 다른 모노 이드 매핑 이전 또는 이후에 구성 할 수 있음) 범주에 의 집합을 잊어 버린 unit캐리어 집합을 제공 하는 집합 (화살표는 단지 ​​기능 화살표)입니다 .

그런 다음 F집합 범주에서이 functor에 인접한 monoid 범주로 functor 를 정의 할 수 있습니다 . 이 functor는 집합 a을 monoid [a], where unit = []및로 매핑하는 functor입니다 mappend = (++).

pseudo-Haskell에서 지금까지의 예를 검토하십시오.

U : Mon  Set -- is our forgetful functor
U (a,mappend,mempty) = a

F : Set  Mon -- is our free functor
F a = ([a],(++),[])

그런 다음 F무료 로 표시 하려면 U잊어 버린 functor에 인접 해 있음을 보여 주어야합니다 . 즉, 위에서 언급했듯이

F a → b 동형이다 a → U b

이제 목표가 monoids F범주 Mon에 있다는 것을 기억하십시오 . 여기서 화살표는 monoid homomorphism입니다. 따라서 monoid homomorphism의 from [a] → b은 함수에 의해 정확하게 설명 될 수 있음 을 보여 주어야합니다 a → b.

하스켈에서 우리의 삶을 것을이의 측면 전화 Set(어, Hask그냥 우리는 척 것을 하스켈 유형의 범주가 설정이다) foldMap에서 전문, Data.Foldable목록에이 유형이를 Monoid m => (a → m) → [a] → m.

이것이 부가적인 결과로 따르는 결과가 있습니다. 특히 잊어 버린 다음 무료로 구축 한 다음 다시 잊어 버린 경우 한 번 잊어 버린 것처럼 이것을 사용하여 모나드 조인을 구축 할 수 있습니다. UFUF~ U(FUF)~ 이래로 UF, 우리 는 우리의 부속물을 정의하는 동 형사상 [a][a]통해 단일성 단일체 동 형체를 전달할 수 있고,리스트 동 형체 [a] → [a]가 유형의 함수 라는 것을 얻습니다 a -> [a].

다음과 같은 용어로 목록을 설명하면이 모든 것을보다 직접 작성할 수 있습니다.

newtype List a = List (forall b. Monoid b => (a -> b) -> b)

무료 모나드

그렇다면 Free Monad 란 무엇입니까?

음, 우리는 이전과 똑같은 일을합니다. 화살표는 모나드 동질성 인 모나드 범주에서 화살표가 자연스런 변형 인 endofunctors 범주까지 잊어 버린 functor U로 시작합니다. 그것에.

그렇다면, 이것은 일반적으로 사용되는 프리 모나드의 개념과 어떤 관련이 있습니까?

무언가가 자유 모나드라는 것을 아는 것은 Free f에서 모나드 동형화를 제공하는 Free f -> m것이에서의 자연적 변형 (functor homomorphism)을 제공하는 것과 동일 하다는 것입니다 f -> m. 기억 F a -> b에 동형해야합니다 a -> U bF가 펑터를 U. U 여기에 매핑 된 모나드에 왼쪽 수반 행렬을 할 수 있도록.

F는 해커 지의 패키지에서 Free사용 하는 유형 과 최소한 동형 free입니다.

또한 무료 목록에 대한 위의 코드와 더 밀접하게 유사하게 구성 할 수 있습니다.

class Algebra f x where
  phi :: f x -> x

newtype Free f a = Free (forall x. Algebra f x => (a -> x) -> x)

코 프리 코 모나드

우리는 잊어 버린 functor가 존재한다고 가정하고 올바른 것을 보면서 비슷한 것을 만들 수 있습니다. cofree functor는 단순히 잊혀진 functor에 / right adjoint /이며, 대칭에 의해 cofree comonad라는 것을 아는 것은 comonad homomorphism을 얻는 w -> Cofree f것이에서 자연적으로 변형되는 것과 같은 것입니다 w -> f.


12
@PauloScardine, 이것은 당신이 아무것도 염려 될 수 있습니다. 내 질문은 고급 데이터 구조를 이해하고 Haskell 개발의 최첨단을 엿볼 수있는 관심에서 비롯된 것입니다. 실제로 Haskell을 작성하는 것이 현재까지 필요한 것은 아닙니다. (그리고 IO 학습 단계를 다시 지나면 더 나아질 것입니다)
David

8
@PauloScardine 무료 모나드를 사용해도 Haskell에서 생산적으로 프로그래밍하기 위해 위의 답변이 필요하지 않습니다. 사실, 범주 이론에 대한 배경 지식이없는 사람에게 이런 식으로 무료 모나드를 공격하는 것은 권장하지 않습니다. 운영 관점에서 그것에 대해 이야기하고 범주 이론에 뛰어 들지 않고 사용하는 방법을 모색하는 방법은 많이 있습니다. 그러나 이론으로 뛰어 들지 않고 그들이 어디에서 왔는지에 대한 질문에 대답하는 것은 불가능합니다. 무료 구성은 범주 이론에서 강력한 도구이지만이를 사용하기 위해이 배경이 필요하지는 않습니다.
Edward KMETT

18
@PauloScardine : Haskell을 효과적으로 활용하고 수행중인 작업을 이해하기 위해서는 미적분학이 필요하지 않습니다. 수학이 재미와 이익을 위해 사용할 수있는 추가 장점 일 때 "이 언어는 수학"이라고 불평하는 것은 약간 이상합니다. 가장 중요한 언어로 이러한 것들을 얻지 못합니다. 왜 엑스트라에 대해 불평하겠습니까? 수학적으로 추론하지 말고 다른 새로운 언어처럼 접근 할 수 있습니다.
Sarah

3
@Sarah : 나는 컴퓨터 이론과 람다 미적분학 열에 무겁지 않은 haskell에 대한 문서 나 IRC 대화를 아직 보지 못했습니다.
Paulo Scardine

11
@PauloScardine 이것은 약간의 구약을 표류하고 있지만 Haskell의 방어에는 비슷한 기술적 인 것들이 다른 모든 프로그래밍 언어에 적용됩니다. Haskell은 사람들이 실제로 그들과 이야기 할 수있는 멋진 편집을 가지고 있습니다. X가 모나드 인 이유 / 어떻게 많은 사람들에게 흥미롭고 IEEE 부동 소수점 표준에 대한 논의는 그렇지 않습니다. 두 경우 모두 결과를 사용할 수 있기 때문에 대부분의 사람들에게 중요하지 않습니다.
David

72

Free Monad (데이터 구조)는 List (데이터 구조)와 같은 Monad (클래스)에서 Monoid (클래스)까지입니다. 사소한 구현으로, 나중에 컨텐츠 결합 방법을 결정할 수 있습니다.


모나드가 무엇인지, 각 모나드는 fmap+ join+ return또는 bind+ 의 특정 (모나드 법 준수) 구현이 필요하다는 것을 알고있을 것입니다 return.

Functor (의 구현 fmap) 가 있다고 가정 하지만 나머지는 런타임에 선택한 값과 선택에 따라 달라집니다. 즉, Monad 속성을 사용할 수는 있지만 나중에 Monad 함수를 선택하려고합니다.

이것은 Free Monad (데이터 구조)를 사용하여 수행 할 수 있습니다.이 기능은 Functor (유형)를 감싼 join것보다 쌓아 놓는 방식으로 Functor (유형)를 포장합니다 .

실제 returnjoin사용하려는 감소 기능에 매개 변수로 제공 할 수 있습니다 foldFree.

foldFree :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
foldFree return join :: Monad m => Free m a -> m a

유형을 설명하기 위해, 우리는 대체 할 수 Functor fMonad mb함께 (m a):

foldFree :: Monad m => (a -> (m a)) -> (m (m a) -> (m a)) -> Free m a -> (m a)

8
이 답변은 그들이 유용 할 수있는 것을 이해한다는 인상을주었습니다.
David

59

Haskell 프리 모나드는 functors의 목록입니다. 비교:

data List a   = Nil    | Cons  a (List a  )

data Free f r = Pure r | Free (f (Free f r))

Pure와 유사 Nil하고 Free유사합니다 Cons. 무료 모나드는 값 목록 대신 펑터 목록을 저장합니다. 기술적으로 다른 데이터 유형을 사용하여 자유 모나드를 구현할 수 있지만 모든 구현은 위의 형식과 동형이어야합니다.

추상 구문 트리가 필요할 때마다 무료 모나드를 사용합니다. 자유 모나드의 기본 기능은 구문 트리의 각 단계 모양입니다.

누군가 이미 연결 한 내 게시물 은 무료 모나드를 사용하여 추상 구문 트리를 작성하는 방법에 대한 몇 가지 예를 제공합니다.


6
나는 당신이 정의를 만드는 것이 아니라 비유를 그리는 것을 알고 있지만, 무료 모나드는 확실히 어떤 의미에서 펑터 목록 과 유사하지 않습니다 . 그것은 functors의 나무에 훨씬 더 가깝습니다.
Tom Ellis

6
나는 내 용어에 동의합니다. 예를 들어 인덱스 코어 패키지를 사용하면 값 대신 펑터를 바인딩한다는 점을 제외하고는 목록 모나드와 같이 동작하는 "자유 모나드 이해"를 정의 할 수 있습니다. 프리 모나드는 모든 하스켈 개념을 펑터 범주로 변환하면리스트가 프리 모나드가된다는 의미에서 펑터 목록입니다. 그런 다음 진정한 펑터 트리가 완전히 달라집니다.
Gabriel Gonzalez

4
모나드는 어떤 의미에서 모노 이드 개념의 분류라는 것이 맞습니다. 따라서 프리 모나드는 프리 모노 이드, 즉리스트와 유사합니다. 그 정도로 당신은 확실히 맞습니다. 그러나 자유 모나드 값의 구조는 목록이 아닙니다. 아래에서 자세히 설명하는 것처럼 나무 입니다.
Tom Ellis

2
@TomEllis 기술적으로는 기본 functor가 제품 functor 인 경우에만 나무입니다. 기본 functor로 sum functor가 있으면 스택 기능과 더 유사합니다.
Gabriel Gonzalez

21

간단한 구체적인 예가 도움이 될 것이라고 생각합니다. 펑터가 있다고 가정 해 봅시다.

data F a = One a | Two a a | Two' a a | Three Int a a a

명백하게 fmap . 그런 다음 Free F a잎 유형이 나무의 유형입니다 a누구의 노드와 태그와 One, Two, Two'Three. One-노드에는 하나의 하위가 있고 Two- Two'노드에는 두 개의 하위가 있고- Three노드에는 세 개의 하위 가 있으며 또한 태그가 있습니다 Int.

Free F모나드입니다. value가있는 잎인 트리에 return매핑 x됩니다 x. t >>= f나뭇잎을보고 나무로 바꿉니다. 리프에 값이 y있으면 해당 리프를 트리로 바꿉니다 f y.

다이어그램은 이것을 더 명확하게하지만 쉽게 그릴 수있는 기능이 없습니다!


14
여러분들이 말하는 것은 무료 모나드는 functor 자체의 모양을 취한다는 것입니다. 따라서 functor가 나무 모양 (제품)이라면, free monad는 나무 모양입니다. 목록과 같은 (합계) 경우, 무료 모나드는 목록과 같습니다. 기능과 유사하다면, 프리 모나드는 기능과 유사합니다. 등등. 이것은 나에게 의미가 있습니다. 따라서 무료 monoid에서와 마찬가지로 mappend의 모든 응용 프로그램을 완전히 새로운 요소를 만드는 것으로 간주합니다. 무료 모나드에서는 펑터의 모든 적용을 완전히 새로운 요소로 취급합니다.
Bartosz Milewski

4
functor가 "sum functor"인 경우에도 결과로 생성되는 free monad는 여전히 나무와 같습니다. 당신은 당신의 트리에 하나 이상의 유형의 노드로 끝납니다 : 합계의 각 구성 요소마다 하나씩. 당신의 "sum functor"가 X-> 1 + X라면, 실제로 당신은리스트를 얻습니다.
Tom Ellis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.