当前位置:  开发笔记 > 前端 > 正文

在Haskell中,如何在不同的Traversable之间进行映射?

如何解决《在Haskell中,如何在不同的Traversable之间进行映射?》经验,为你挑选了1个好方法。

我们知道,fmap“签名是(a -> b) -> f a -> f b其中f的一个Functor

为了尽可能地通用和更好地分解因子代码,人们可能希望将“事物列表”映射到另一个可能不同的“事物列表”。凭直觉,我不明白为什么它不应该或不可能。

我正在寻找的功能gmap与该功能具有相同的功能,fmap但具有该签名gmap :: (a -> b) -> (f a) -> (g b),在该功能中,我允许到达和离开容器有所不同。

我不确定这在一般情况下where fgare 是否有意义Functors,但是Traversable假设我最感兴趣的是遍历数据,那么“事物列表”的想法在本质上听起来更像是课堂上所捕获的。

所以也许签名应该是gmap :: (Traversable f, Traversable g) => (a -> b) -> (f a) -> (g b)

即使g具有不同的性质f,它仍然可以从左到右遍历,因此仍然觉得应该能够将的第k个被访问元素映射f到的第k个被访问元素g

假设我的想法没有错,Haskell中是否有这样的功能?

从本质上讲,我的问题是,您将如何以最简洁,最优雅的方式从Haskell中的一个类似列表的事物转换为另一个?



1> Justin L...:

我们经常在Haskell中使用一种技巧来证明事情不可能发生,那就是尝试使用它来产生“假”,也就是产生一个type值

data Void

没有构造函数的类型。如果可能的话,使用您的类型签名来产生type的值Void,那么就不可能实现您的类型签名。这也被称为“荒谬的还原”,或“矛盾相抵触”。如果您的类型签名允许我们产生类型的值Void...那么,“显然”您的类型签名是双层的,无法实现。

在这种情况下,我们正在“返回”一个Traversable实例,所以我们使用Traversablelike (,) Void

instance Traversable ((,) w) where
    traverse f (x, y) = (x,) <$> f y

现在,让我们f用作任何旧的仿函数。它可以是任何东西...让我们使用,Maybe因为似乎每个人都已经理解了。

然后,您可以编写:

gmap :: (a -> b) -> Maybe a -> (Void, b)

哦,不,那是不对的...看来,使用gmap可以Void通过传入任何旧内容来创建一个:

gmap :: (() -> ()) -> Maybe () -> (Void, ())

所以现在我的创建策略是Void

bad :: Void
bad = fst (gmap id Nothing)

因为Void没有构造函数,所以不应该bad :: Void存在类型的值(忽略诸如无限循环或部分函数之类的东西)。因此,如果仅存在的话gmap就可以允许我们创建类型的值Void...,则必须意味着它gmap不能以您给定的形式存在。


对于更笼统的问题,Traversable工作原理的“原因” 是它只能修改结构。它无法创建它们。在这里,您要创建的值g b,但Traversable不能“创建”它,而只能“转换”它。您的误解可能是因为您认为这Traversable是“列表式”类型类:事实并非如此。使用[]作为原型可能会误入歧途导致你。

我“典型” Traversable的想象类型类的属性是Map k,来自容器Data.Map:a Map不是a,而是与键关联的值。对它的任何操作都必须能够尊重此关联属性...并且不能将其视为没有额外结构的大列表。

那么,什么是可能是这样的:

replace :: (Foldable f, Traversable g) => f a -> g b -> g a

其中的所有值g b都由的所有值代替f a。如果您正在寻找一种练习,那么写这个实际上很有趣。基本上,replace保持相同的结构,该g a有,但只是更换。所以,你可以“创造”一个g af a只要你有一个“榜样g b”,可以这么说。如果您使用了类似的方法:

replace :: [a] -> Map k b -> Map k a

然后replace将第二张地图中的所有值替换为列表中的项目,并以适当的键值替换它们。

然后您可以编写:

gmap :: (Traversable a, Traversable g) => (a -> b) -> f a -> g c -> g b

在此处以g a您要复制的结构的“示例”为例。

能够“构建” Haskell常见类型类中的结构的最接近的东西是IsList,来自https://hackage.haskell.org/package/base-4.12.0.0/docs/GHC-Exts.html#t:IsList

此类型类为您提供了fromList和的两个函数toList,因此您可以编写:

throughIsList :: (IsList l, IsList m, Item l ~ Item m) => l -> m
throughIsList = fromList . toList

并使其在Functors上工作:

gmap :: (IsList (f a), IsList (g b), Item (f a) ~ a, Item (g b) ~ b) => (a -> b) -> f a -> g b
gmap f = fromList . map f . toList

现在的问题是,大多数Functors都不是IsList...的实例,而且许多实际实例也不是总数。因此,对于大多数Functors 来说,它并不是很有用。


因此,最后我认为没有令人满意的答案。如果您正在做的事情依赖于一个很好的答案(而不是“否”的答案)的事实……也许我可以问一下您的“最终目标”是什么?您打算将这种类型用于什么?

(例如,在那里的人问这样的问题的情况下90%“是有办法,我可以转换单子”或类似的东西,通常他们想要做的东西一般,而是他们有特定的类型,他们中有心神。)

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有