Haskell“伪函子”
我有一个多项式,
data Poly a = Poly [a]
我希望能够执行类似 fmap (take 3) polynomial
的操作,但我不能,因为 Poly
并不是真正的函子,因为我在 fmap
中使用的 f
只能是 [a] -> 类型[b]
,而不是a -> b.
。
有什么成语或方式可以表达我想要的吗?
编辑:这是一个执行我想要的用法的函数
myMap :: ([a] ->[b]) -> P a -> P b
myMap f (P x) = P (f x)
:
*Main> myMap (take 3) (P [1..])
P [1,2,3]
您可以从类型 sig 中看到它几乎 fmap,但不完全是。我显然有能力为 myMap
编写代码,但我只是想知道是否应该使用另一种习惯用法。
I have a polynomial
data Poly a = Poly [a]
I would like to be able to do something like fmap (take 3) polynomial
but I can't since Poly
isn't really a functor in that the f
I use in fmap
can only be of type [a] -> [b]
, not a -> b
.
Is there an idiom or way I can express what I want?
EDIT: here is a function which does what I want
myMap :: ([a] ->[b]) -> P a -> P b
myMap f (P x) = P (f x)
usage:
*Main> myMap (take 3) (P [1..])
P [1,2,3]
You can see from the type sig that it's almost fmap, but not quite. I'm obviously capable of writing the code for myMap
, but I just want to know if there's another idiom I should be using instead.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于您允许将任何函数应用于系数列表,因此您的数据类型实际上仅用于两个目的。
Poly [a]
与[a]
不同。如果您不需要其中任何一个,您也可以使用类型别名。
现在您可以直接在其上应用任何列表功能。
另一方面,如果您想要一个不同的类型,您可能会发现
newtype
包很有用。例如,给出这个例子。您现在可以编写类似的内容,
尽管如果您的
myMap
足以满足您的目的,那么这可能有点过分了。除此之外,我认为以这种方式公开数据类型的表示首先可能不是一个好主意,因为它会使代码的其余部分密切依赖于这种表示。
这使得以后更难更改为不同的表示形式。例如,您可能想要更改为稀疏表示,例如
Int 是项的幂。我建议考虑一下您想要公开哪些操作,并将自己限制在这些操作范围内。例如,拥有一个基于每个元素工作的 Functor 实例可能是有意义的。
现在,对稀疏表示的更改使客户端代码保持不变。只有实例(以及依赖于表示的少数其他函数)需要更改。
Since you allow any function to be applied to the list of coefficients, your data type only really serves two purposes.
Poly [a]
is distinct from[a]
.If you don't need either of these, you might as well use a type alias.
Now you can apply any list function on it directly.
If, on the other hand, you want a distinct type, you might find the
newtype
package useful. For example, given this instance.You can now write things like
although this might be overkill if your
myMap
is sufficient for your purposes.All this aside, I think that exposing the representation of your data type in such a way might not be a good idea in the first place, as it can leave the rest of your code intimately dependent on this representation.
This makes it harder to change to a different representation at a later time. For example, you might want to change to a sparse representation like
where the
Int
is the power of the term. I suggest thinking about what operations you want to expose, and limiting yourself to those. For example, it might make sense to have aFunctor
instance that works on a per-element basis.Now, the change to the sparse representation leaves client code unchanged. Only the instance (and the handful of other functions that depend on the representation) will have to change.
这不起作用,但我认为无论如何,它都足够有趣,值得分享:
我们现在有一个在
a
上参数化的 Poly 类型,但实际上a
必须是一个列表:现在我们可以尝试为这种类型编写一个 Functor 实例:
这是行不通的。有趣的是,我们甚至无法真正编写
myMap
:如果我们尝试这样做,我们会得到
当然我们可以使用类型注释来修复它:
但如果没有它,这与 fmap 遇到的问题类似。 Functor 只是没有任何地方可以输出“我保证总是使用列表”的额外上下文,事实上它确实不能。例如,您始终可以说
undefined :: Poly Int
。简而言之,我不认为真的有一个习语可以表达这一点(实际上,有人可能会提供足够的 ghc 扩展魔法来做到这一点)。当然不是现有的。This doesn't work but I thought it was interesting enough to share anyway:
We now have a type Poly that's parameterized on
a
, but effectivelya
has to be a list:Now we can try and write an instance of
Functor
for this type:That's not going to work. Interestingly enough, we can't even really write
myMap
:If we try this we get
Of course we can fix it with a type annotation:
But without it, it's a similar problem to what fmap had. Functor just doesn't have anywhere to out this extra context of "I promise always to use lists", and indeed it can't really. You can always say
undefined :: Poly Int
for example. In short, I don't think there's really an idiom that could express this (actually, someone will probably come along with enough ghc extension magic to do it). Certainly not an existing one.