描述Free monad的一种方法是说它是endofunctors类别(某些类别C
)中的 initial monoid,其对象是来自{{1}的endofunctors } C
,箭头是它们之间的自然变换。如果我们将C
作为C
,那么endofunctor就是haskell中的Hask
,它是来自Functor
的仿函数,其中* -> *
表示{的对象{1}}
根据初始性,从*
中的endofunctor Hask
到monoid t
的任何地图都会导致从m
到End(Hask)
的地图。
否则,从Functor Free t
到Monad m
的任何自然转换都会导致从t
到m
的自然转换
我原本希望能够编写一个函数
Free t
但是这不能统一,而以下工作
m
或带签名的概括
free :: (Functor t, Monad m) => (∀ a. t a → m a) → (∀ a. Free t a → m a)
free f (Pure a) = return a
free f (Free (tfta :: t (Free t a))) =
f (fmap (free f) tfta)
我是否在类别理论或Haskell的翻译中犯了错误?
我有兴趣在这里听到一些智慧......
PS:启用该代码的代码
free :: (Functor t, Monad m) => (t (m a) → m a) → (Free t a → m a)
free f (Pure a) = return a
free f (Free (tfta :: t (Free t a))) =
f (fmap (free f) tfta)
答案 0 :(得分:7)
Haskell翻译似乎错了。一个很大的提示是你的free
实现并没有在任何地方使用monadic bind(或join)。您可以使用以下定义找到free
foldFree
:
free :: Monad m => (forall x. t x -> m x) -> (forall a. Free t a -> m a)
free f (Pure a) = return a
free f (Free fs) = f fs >>= free f
关键点是f
专门针对t (Free t a) -> m (Free t a)
,从而一举消除了一个Free
层。
答案 1 :(得分:3)
我不了解类别理论部分,但是Haskell部分绝对不能用原始实现和原始类型签名进行良好的输入。
鉴于
Free tfta
当你在tfta :: t (Free t a)
f :: forall a. t a -> m a
free :: (forall a. t a -> m a) -> forall a. Free t a -> m a
上进行模式匹配时,你会得到
free f :: forall a. Free t a -> m a
因此
fmap (free f) :: forall a. t (Free t a) -> t (m a)
导致
t (m a)
为了能够将m a
折叠到您想要的f
,您需要在其上应用t
(以及#34;将m
变为m
")然后利用f . fmap (free f) :: forall a. t (Free t a) -> m (m a)
join . f . fmap (free f) :: forall a. t (Free t a) -> m a
是Monad的事实:
free
这意味着您可以通过更改{-# LANGUAGE RankNTypes, UnicodeSyntax #-}
import Control.Monad.Free
import Control.Monad
free :: (Functor t, Monad m) => (∀ a. t a → m a) → (∀ a. Free t a → m a)
free f (Pure a) = return a
free f (Free tfta) = join . f . fmap (free f) $ tfta
的第二个分支来修复原始定义:
var john = {
peter: {},
one: function() { alert('one'); },
two: function() {
peter.handler = function() {
john.one(); // JS cannot find one(). one() undefined.
Console.log(this); // object peter
}
Console.log(this); // object john
}
}
这可能是你想要的,但也许可能是你想要的:)