Generics 关于自由箭头的有用操作
我们知道免费的单子是有用的,像这样的软件包只关心应用程序特定的效果,而不关心单子结构本身,从而使定义新的单子变得容易 我们可以很容易地定义“自由箭头”,类似于自由单子的定义:Generics 关于自由箭头的有用操作,generics,haskell,arrows,Generics,Haskell,Arrows,我们知道免费的单子是有用的,像这样的软件包只关心应用程序特定的效果,而不关心单子结构本身,从而使定义新的单子变得容易 我们可以很容易地定义“自由箭头”,类似于自由单子的定义: {-# LANGUAGE GADTs #-} module FreeA ( FreeA, effect ) where import Prelude hiding ((.), id) import Control.Category import Control.Arrow import Con
{-# LANGUAGE GADTs #-}
module FreeA
( FreeA, effect
) where
import Prelude hiding ((.), id)
import Control.Category
import Control.Arrow
import Control.Applicative
import Data.Monoid
data FreeA eff a b where
Pure :: (a -> b) -> FreeA eff a b
Effect :: eff a b -> FreeA eff a b
Seq :: FreeA eff a b -> FreeA eff b c -> FreeA eff a c
Par :: FreeA eff a₁ b₁ -> FreeA eff a₂ b₂ -> FreeA eff (a₁, a₂) (b₁, b₂)
effect :: eff a b -> FreeA eff a b
effect = Effect
instance Category (FreeA eff) where
id = Pure id
(.) = flip Seq
instance Arrow (FreeA eff) where
arr = Pure
first f = Par f id
second f = Par id f
(***) = Par
我的问题是,对自由箭头最有用的通用操作是什么?对于我的特殊应用程序,我需要以下两种特殊情况:
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
analyze :: forall f eff a₀ b₀ r. (Applicative f, Monoid r)
=> (forall a b. eff a b -> f r)
-> FreeA eff a₀ b₀ -> f r
analyze visit = go
where
go :: forall a b. FreeA eff a b -> f r
go arr = case arr of
Pure _ -> pure mempty
Seq f₁ f₂ -> mappend <$> go f₁ <*> go f₂
Par f₁ f₂ -> mappend <$> go f₁ <*> go f₂
Effect eff -> visit eff
evalA :: forall eff arr a₀ b₀. (Arrow arr) => (forall a b. eff a b -> arr a b) -> FreeA eff a₀ b₀ -> arr a₀ b₀
evalA exec = go
where
go :: forall a b. FreeA eff a b -> arr a b
go freeA = case freeA of
Pure f -> arr f
Seq f₁ f₂ -> go f₂ . go f₁
Par f₁ f₂ -> go f₁ *** go f₂
Effect eff -> exec eff
{-#语言类型}
{-#语言范围类型变量#-}
分析::对于所有f eff a₀ B₀ R(应用f,幺半群r)
=>(对于所有a b.效果a b->f r)
->自由有效₀ B₀ -> f r
分析访问=go
哪里
全部a b。自由效果a b->f r
go arr=情况arr
纯记忆->纯记忆
序号f₁ F₂ -> mappend go f₁ 去f₂
巴尔夫₁ F₂ -> mappend go f₁ 去f₂
效果效果->访问效果
evalA::用于所有效果₀ B₀. (箭头arr)=>(对于所有a b.效果a b->a b)-自由a效果a₀ B₀ -> 阿拉₀ B₀
evalA exec=go
哪里
全部a b。FreeA eff a b->arr a b
自由行动
纯f->arr f
序号f₁ F₂ -> 去f₂ . 去f₁
巴尔夫₁ F₂ -> 去f₁ *** 去f₂
效果效果->执行效果
但是对于为什么这些(而不是其他)是有用的,我没有任何理论上的论据。一个自由函子与一个健忘函子是左伴随的。对于附加语,您需要具有同构(在
x
和y
中为自然):
这与Arrow
实例类别中的箭头相同,但添加了Arrow
约束。因为健忘函子只会忘记约束,所以我们不需要用Haskell表示它。这将上述同构转化为两个函数:
leftAdjunct :: (FreeA x :~> y) -> x :~> y
rightAdjunct :: Arrow y => (x :~> y) -> FreeA x :~> y
leftAttachment
还应该有一个箭头y
约束,但事实证明它在实现中从来都不需要。实际上,对于更有用的单元
,有一个非常简单的实现:
unit :: x :~> FreeA x
leftAdjunct f = f . unit
unit
是你的效果
和righattachment
是你的evalA
。因此,您完全具备附加功能所需的功能!您需要证明leftappendenct
和righappendenct
是同构的。最简单的方法是证明righattachment unit=id
,在您的案例中evalA effect=id
,这很简单
那么分析呢?这是专用于常量箭头的evalA
,结果的Monoid
约束专用于应用的Monoid。即
analyze visit = getApp . getConstArr . evalA (ConstArr . Ap . visit)
与
和Ap
from。(编辑:自GHC 8.6以来,它也位于Data.Monoid中的base中)
编辑:我差点忘了,FreeA应该是高阶函子!Edit2:仔细想想,也可以用rightaxtinct
和unit
实现
顺便说一句:还有另一种定义自由函子的方法,我最近给它加了一个例子。它不支持种类*->*->*
(编辑:现在支持!),但代码可以调整为自由箭头:
newtype FreeA eff a b = FreeA { runFreeA :: forall arr. Arrow arr => (eff :~> arr) -> arr a b }
evalA f a = runFreeA a f
effect a = FreeA $ \k -> k a
instance Category (FreeA f) where
id = FreeA $ const id
FreeA f . FreeA g = FreeA $ \k -> f k . g k
instance Arrow (FreeA f) where
arr f = FreeA $ const (arr f)
first (FreeA f) = FreeA $ \k -> first (f k)
second (FreeA f) = FreeA $ \k -> second (f k)
FreeA f *** FreeA g = FreeA $ \k -> f k *** g k
FreeA f &&& FreeA g = FreeA $ \k -> f k &&& g k
如果你不需要你的FreeA
提供的内省,这个FreeA
可能更快。你确定你的FreeA是真正免费的吗?这是一个真实的问题,因为我不知道答案。我担心这个问题对StackOverflow来说可能太可怕了。但我肯定不会给它打上标记;)请注意,arr id
只是id
哦,我是指您对first
和second
的定义。类别实例没有关联,是吗?你能把a.b.c和a.b.c区分开,不是吗?
analyze visit = getApp . getConstArr . evalA (ConstArr . Ap . visit)
newtype ConstArr m a b = ConstArr { getConstArr :: m }
hfmap :: (x :~> y) -> FreeA x :~> FreeA y
hfmap f = evalA (effect . f)
newtype FreeA eff a b = FreeA { runFreeA :: forall arr. Arrow arr => (eff :~> arr) -> arr a b }
evalA f a = runFreeA a f
effect a = FreeA $ \k -> k a
instance Category (FreeA f) where
id = FreeA $ const id
FreeA f . FreeA g = FreeA $ \k -> f k . g k
instance Arrow (FreeA f) where
arr f = FreeA $ const (arr f)
first (FreeA f) = FreeA $ \k -> first (f k)
second (FreeA f) = FreeA $ \k -> second (f k)
FreeA f *** FreeA g = FreeA $ \k -> f k *** g k
FreeA f &&& FreeA g = FreeA $ \k -> f k &&& g k