在Applicative深入研究的同时,我来到了Traversable.虽然我已经Foldable从LYHGG知道了,但我还没有见过前者,所以我开始阅读关于Traversable的Haskell wiki.
在阅读它时,我理解为什么它Foldable.fold是平行的Traversable.sequenceA并且Foldable.foldMap是平行的Traversable.traverse.
我也看到每个Traversable也是a Foldable和a Functor,sequenceA并且traversal彼此有默认实现:
traverse f = sequenceA . fmap f
sequenceA = traverse id
Run Code Online (Sandbox Code Playgroud)
所以,正如我在LYHGG中看到的那样,它foldMap是一个最小的完整定义Foldable,我认为,它是平行的traverse,所以fold(它是平行的sequenceA)也是一个最小的完整定义(它不是)... Foldable是不是Functor喜欢Traversable的,所以我们不能申请这个:
foldMap f = fold . fmap f
fold = foldMap id -- this is ok
Run Code Online (Sandbox Code Playgroud)
为什么不是每Foldable一个 …
为了证明例如类别法适用于数据类型的某些操作,如何确定如何定义相等?考虑以下类型来表示布尔表达式:
data Exp
= ETrue
| EFalse
| EAnd Exp Exp
deriving (Eq)
Run Code Online (Sandbox Code Playgroud)
尝试证明Exp与身份ETrue和运算符形成一个类别是否可行:
(<&>) = EAnd
Run Code Online (Sandbox Code Playgroud)
没有重新定义Eq实例?使用的默认实例式的左身份法符,即:
ETrue <&> e == e
Run Code Online (Sandbox Code Playgroud)
评估为False.但是,定义一个eval函数:
eval ETrue = True
eval EFalse = False
eval (EAnd e1 e2) = eval e1 && eval e2
Run Code Online (Sandbox Code Playgroud)
和Eq实例为:
instance Eq Exp where
e1 == e2 = eval e1 == eval e2
Run Code Online (Sandbox Code Playgroud)
解决了这个问题.是否(==)对声称满足此类法律的一般要求进行比较,或者是否足以说法律适用于特定类型的平等运营商?
想象一下,我们有一个SortBinTree类型构造函数,例如,
data SortBinTree a = EmptyNode | Node a (SortBinTree a) (SortBinTree a);
Run Code Online (Sandbox Code Playgroud)
它只有在类型类a的实例时才有意义Ord,因此大多数函数:: (Ord a) =>在其声明的开头都有,特别是从列表中创建这样一个树的函数.但是要教Haskell,这SortBinTree是Functor类型类的一个实例,我们必须编写类似的东西
instance Functor SortBinTree where
fmap g tree = ...
Run Code Online (Sandbox Code Playgroud)
这里的问题是我们必须处理g :: a->b,其中b不一定是Ord类类的实例.这使得编写这样的函数成为问题,因为在创建类型的元素时我们不能使用不等式SortBinTree b.
这里有标准的解决方法吗?任何fmap只为案例定义的方法b是在Ord类型类中?
地图函数(Seq.map,List.map等)是否具有隐含的后置条件,即输出与输入具有相同数量的项目?更进一步,如果我们有某种Tree.map函数,是否假设输入和输出树的"形状"是相同的?
我问的原因是我总是做出这样的假设(我怀疑很多映射在序列上的代码也会这样做),但后来我发现如果映射函数产生重复,Set.map可以返回一个较小的集合. .因此,我的假设无效,或者Set不应被视为用于映射目的的序列.这是什么?
在我的项目的其他地方,我已经定义了一个walk遍历AST 的函数,该函数的核心用于foldl将访问树中每个节点的结果减少为单个幺半群结果(例如,从特殊结果生成"符号表")树中的节点).
我的问题是:是否可以将这两种方法结合起来并使用像我的函数这样的walk函数:
walk :: Monoid a => (Node -> a) -> a -> Node -> a
walk f acc n = foldl (walk f) (acc <> f n) children
where
children = case n of
Blockquote b -> b
DocBlock d -> d
FunctionDeclaration {} -> functionBody n
List l -> l
ListItem i -> i …Run Code Online (Sandbox Code Playgroud) haskell ×4
functor ×3
applicative ×1
f# ×1
fold ×1
foldable ×1
monads ×1
parsec ×1
reader-monad ×1
traversable ×1