我对Haskell库Control.Monad.Free中的函数hoistfree有一些疑问。给定两个仿函数之间的变换f
,hoistfree f在相应的自由monad之间产生一个态射。这是它的定义。
hoistFree :: Functor g => (forall a. f a -> g a) -> Free f b -> Free g b
hoistFree _ (Pure a) = Pure a
hoistFree f (Free as) = Free (hoistFree f <$> f as)
问题1 Haskell如何知道<$>
是与g
相关联的地图,而不是f
,Free f
或{{1 }}?
问题2 为什么hoistfree尚未被定义为
Free g
如果hoistFree :: Functor g => (forall a. f a -> g a) -> Free f b -> Free g b
hoistFree _ (Pure a) = Pure a
hoistFree f (Free as) = Free (f (hoistFree f <$> as))
是自然变换,则这两个定义重合。然而,第二个定义总是满足关系
f
看起来很自然。此外,还有一些基本功能可以使用hoistfree f = iter (wrap . f) . map return
来表达。例如,
iter_map f g = iter f . map g
问题3 是否在某处定义了iter_map?它看起来像monadic mapreduce。我在基础库中没有看到它。融合iter和map有什么好处吗?在其他一些语言中,情况确实如此,但我不确定Haskell。
答案 0 :(得分:5)
问题1
由于类型推断,从<$>
中选择g
。的确,在
Free (hoistFree f <$> f as)
f as
的类型为g <something>
,因此<$>
是由Functor g
指定的。{/ p>
问题2
我认为,在Haskell中,f
始终是一种自然的转变。根据参数/自由定理,f a -> g a
中的任何多态函数a
都必须是自然的。
两个定义都是等价的,我不确定是否有任何一个是“最好的”。也许你的是。或者也许原始的在实践中有更好的表现。它看起来有点像关联运算符的foldr
vs foldl'
参数,其中没有明显的赢家。
问题3 不知道。