Haskell"伪函子"

Xod*_*rap 5 haskell functor

我有一个多项式

data Poly a = Poly [a]
Run Code Online (Sandbox Code Playgroud)

我希望能够做类似的事情,fmap (take 3) polynomial但我不能因为我Poly不是真正的函子,因为f我使用的fmap只能是类型[a] -> [b],而不是a -> b.

是否有成语或方式可以表达我想要的东西?


编辑:这是一个功能,它做我想要的

myMap :: ([a] ->[b]) -> P a -> P b
myMap f (P x) = P (f x)
Run Code Online (Sandbox Code Playgroud)

用法:

*Main> myMap (take 3) (P [1..])
P [1,2,3]
Run Code Online (Sandbox Code Playgroud)

你可以从类型sig看到它几乎是 fmap,但并不完全.我显然有能力编写代码myMap,但我只是想知道我是否应该使用另一个成语.

ham*_*mar 10

由于您允许将任何函数应用于系数列表,因此您的数据类型实际上只有两个用途.

  • 你得到额外的类型安全,因为a Poly [a]是不同的[a].
  • 您可以定义不同的实例.

如果您不需要其中任何一个,您也可以使用类型别名.

type Poly a = [a]
Run Code Online (Sandbox Code Playgroud)

现在您可以直接在其上应用任何列表功能.

另一方面,如果您想要一个不同的类型,您可能会发现newtype有用.例如,给定此实例.

instance Newtype (Poly a) [a] where
  pack = Poly
  unpack (Poly x) = x
Run Code Online (Sandbox Code Playgroud)

你现在可以写像

foo :: Poly a -> Poly a
foo = over Poly (take 3)
Run Code Online (Sandbox Code Playgroud)

虽然如果你myMap的目的足够了,这可能是过度的.


除此之外,我认为以这种方式公开数据类型的表示可能不是一个好主意,因为它可以使代码的其余部分紧密依赖于此表示.

这使得以后更改为不同的表示更加困难.例如,您可能希望更改为稀疏表示

data Poly a = Poly [(a, Int)]
Run Code Online (Sandbox Code Playgroud)

Int是术语的力量所在.我建议考虑你想要公开的操作,并限制自己.例如,拥有一个Functor基于每个元素的实例可能是有意义的.

instance Functor Poly where
    fmap f (Poly x) = Poly $ map f x
Run Code Online (Sandbox Code Playgroud)

现在,对稀疏表示的更改使客户端代码保持不变.只有实例(以及依赖于表示的少数其他函数)才必须更改.

instance Functor Poly where
    fmap f (Poly x) = Poly $ map (first f) x
Run Code Online (Sandbox Code Playgroud)