Haskell Traversable1中的上下文边界
在包中,我找到了以下定义:Haskell Traversable1中的上下文边界,haskell,Haskell,在包中,我找到了以下定义: class (Foldable1 t, Traversable t) => Traversable1 t where traverse1 :: Apply f => (a -> f b) -> t a -> f (t b) sequence1 :: Apply f => t (f b) -> f (t b) sequence1 = traverse1 id traverse1 f = sequence1 .
class (Foldable1 t, Traversable t) => Traversable1 t where
traverse1 :: Apply f => (a -> f b) -> t a -> f (t b)
sequence1 :: Apply f => t (f b) -> f (t b)
sequence1 = traverse1 id
traverse1 f = sequence1 . fmap f
为什么上下文边界设置为
Apply
(一个Applicative
,没有pure
),而不是Functor
?显然,您需要覆盖其中一个定义,因此,使用“just”aFunctor
这是不可能的吗?这只是一个稍微严格的可遍历
——所有可遍历1
都是可遍历
,但反之亦然。关于为什么Traversable
s需要Applicative
s的更多细节,也许值得一看。从手势上讲,如果你有一个函子,如果它包含很多值,就不可能对该函子的效果进行“排序”,因为你的“注入”函数(a->fb)
是获得b
s的唯一方法,你不能加入f
的层
但是,广义地说,当您定义可遍历的时,您只需要使用无效果注入函数,pure
,作为“默认”值,这正是Traversable1
所消除的。这就是为什么NonEmpty
是一个实例,而[]
不是
为了使事情具体化,考虑这些标识函数的实例实例,<代码>可能,<代码>非空列表,以及常规<代码> []/COD> < /P>
newtype Id a = Id a
instance Functor Id where fmap f (Id a) = Id (f a)
instance Applicative Id where
pure = Id
(Id f) <*> (Id x) = Id (f x)
我们需要pure
来处理Maybe
的“默认”Nothing
情况(只比Id
稍微复杂一点)
由于我们只使用了()
,而不是纯
,所以我们可以将其作为可遍历的1
实例
instance Traversable1 NonEmpty where
traverse1 inj (NonEmpty a []) = (`NonEmpty` []) <$> inj a
traverse1 inj (NonEmpty a (b: bs)) =
(\a' (NonEmpty b' bs') -> NonEmpty a' (b': bs'))
<$> inj a
<.> traverse1 inj (NonEmpty b bs)
编辑:最初我对Traversable1 NonEmpty
的定义是轻描淡写的。目前的版本确实有效,但是眼睛更难看。以前我尝试过遍历内部列表,这在精神上是有效的,因为非空的的第二个插槽中的[]
有第一个插槽来帮助它,但这不能直接工作,因为内部列表有一个空的大小写[]
,需要纯。相反,我们必须通过在第一个位置“偷取”始终存在的a
,然后在遍历后替换它来避免这种空情况
该方法(和数据类型定义)与半群和半群ID库本身中使用的版本非常相似,并且非常有用,因为它们可以利用常规[]
后面的库动力,但是,如果我们对非空
的定义稍有不同,我们就会发现可遍历的和可遍历的1
之间存在大量的并行性。事实上,Traversable1
实例可以存在,这确实是数据类型本身的一个特征——定义基本相同
import Data.Monoid
import qualified Data.Semigroup as Se
import Data.Traversable
import Data.Foldable
import Data.Semigroup.Foldable
import Data.Semigroup.Traversable
import Data.Functor.Apply
import Control.Applicative
-- For comparison
data List a = Empty | List a (List a)
data NonEmpty a = One a | Many a (NonEmpty a)
instance Functor NonEmpty where
fmap f (One a) = One (f a)
fmap f (Many a as) = Many (f a) (fmap f as)
instance Apply NonEmpty where
(One f) <.> (One a) = One (f a)
(One f) <.> (Many a _) = One (f a)
(Many f _) <.> (One a) = One (f a)
(Many f fs) <.> (Many a as) = Many (f a) (fs <.> as)
instance Applicative NonEmpty where
pure = One
(<*>) = (<.>)
instance Foldable NonEmpty where
foldMap f (One a) = f a
foldMap f (Many a as) = f a <> foldMap f as
instance Foldable1 NonEmpty where
foldMap1 f (One a) = f a
-- Core distinction: we use the Semigroup.<> instead of the Monoid.<>
foldMap1 f (Many a as) = f a Se.<> foldMap1 f as
instance Traversable NonEmpty where
traverse inj (One a) = One <$> inj a
traverse inj (Many a as) = Many <$> inj a <*> traverse inj as
instance Traversable1 NonEmpty where
traverse1 inj (One a) = One <$> inj a
traverse1 inj (Many a as) = Many <$> inj a <.> traverse1 inj as
导入数据.Monoid
导入限定数据。半群为Se
导入数据。可遍历
导入数据。可折叠
导入Data.Semigroup.Foldable
导入Data.Semigroup.Traversable
导入数据.Functor.Apply
导入控制
--作比较
数据列表a=空|列表a(列表a)
数据非空a=一个a |多个a(非空a)
实例函子非空,其中
fmap f(一个a)=一(一个)
fmap f(多个a为)=多个(f为)(fmap f为)
实例Apply非空,其中
(一个f)(一个a)=一个(f a)
(一个f)(多个a _)=一个(f a)
(多个f_u2;)(一个a)=一个(f a)
(多个f fs)(多个a as)=多个(f a)(fs as)
实例应用程序非空where
纯=一
() = ()
实例可折叠非空where
折叠图f(一个)=f a
折叠映射f(多个a)=f a折叠映射f a
实例Foldable1非空,其中
折叠贴图1 f(一个a)=f a
--核心区别:我们使用半群。而不是幺半群。
foldMap1 f(多a as)=f a Se。foldMap1 f as
实例可遍历非空where
横向输入(一个a)=一个输入a
导线输入(多个等于)=导线输入的多个等于
实例Traversable1非空,其中
导线1 inj(一个a)=一个inj a
traverse1 inj(多个a as)=多个a traverse1 inj as
data NonEmpty a = NonEmpty a [a]
instance Functor NonEmpty where fmap f (NonEmpty a as) = NonEmpty (f a) (fmap f as)
instance Apply NonEmpty where
(NonEmpty f fs) <.> (NonEmpty x xs) = NonEmpty (f x) (fs <*> xs)
instance Pointed NonEmpty where
point a = NonEmpty a []
instance Applicative NonEmpty where
(<*>) = (<.>)
pure = point
instance Traversable NonEmpty where
traverse inj (NonEmpty a as) = NonEmpty <$> inj a <*> (traverse inj a as)
instance Traversable1 NonEmpty where
traverse1 inj (NonEmpty a []) = (`NonEmpty` []) <$> inj a
traverse1 inj (NonEmpty a (b: bs)) =
(\a' (NonEmpty b' bs') -> NonEmpty a' (b': bs'))
<$> inj a
<.> traverse1 inj (NonEmpty b bs)
instance Traversable [] where
traverse _ [] = pure []
traverse inj (x:xs) = (:) <$> inj x <*> traverse inj xs
import Data.Monoid
import qualified Data.Semigroup as Se
import Data.Traversable
import Data.Foldable
import Data.Semigroup.Foldable
import Data.Semigroup.Traversable
import Data.Functor.Apply
import Control.Applicative
-- For comparison
data List a = Empty | List a (List a)
data NonEmpty a = One a | Many a (NonEmpty a)
instance Functor NonEmpty where
fmap f (One a) = One (f a)
fmap f (Many a as) = Many (f a) (fmap f as)
instance Apply NonEmpty where
(One f) <.> (One a) = One (f a)
(One f) <.> (Many a _) = One (f a)
(Many f _) <.> (One a) = One (f a)
(Many f fs) <.> (Many a as) = Many (f a) (fs <.> as)
instance Applicative NonEmpty where
pure = One
(<*>) = (<.>)
instance Foldable NonEmpty where
foldMap f (One a) = f a
foldMap f (Many a as) = f a <> foldMap f as
instance Foldable1 NonEmpty where
foldMap1 f (One a) = f a
-- Core distinction: we use the Semigroup.<> instead of the Monoid.<>
foldMap1 f (Many a as) = f a Se.<> foldMap1 f as
instance Traversable NonEmpty where
traverse inj (One a) = One <$> inj a
traverse inj (Many a as) = Many <$> inj a <*> traverse inj as
instance Traversable1 NonEmpty where
traverse1 inj (One a) = One <$> inj a
traverse1 inj (Many a as) = Many <$> inj a <.> traverse1 inj as