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