Functor类中(<$)的目的是什么?

sdc*_*vvc 12 haskell functor

Functor类包含一个隐藏的第二构件:

class Functor f where
  fmap :: (a -> b) -> f a -> f b
  (GHC.Base.<$) :: a -> f b -> f a
Run Code Online (Sandbox Code Playgroud)

文档:

用相同的值替换输入中的所有位置.默认定义是fmap . const,但可以使用更高效的版本覆盖它.

我想知道更多.为什么这个fmap . const成语是一个单独的成员?替代实施如何更有效?这个组合器的应用是什么?

Phi*_* JF 9

它作为成员包含在内,允许用户根据速度进行自定义,我想这是因为它使它与之一致>>.

我认为在读者monad的情况下它可能会更快((->) r).

x <$ _ = const x
Run Code Online (Sandbox Code Playgroud)

VS

x <$ fa = fmap (const x) fa = (const x) . fa
Run Code Online (Sandbox Code Playgroud)

虽然,这确实是编译器优化的问题.并且,它似乎没有为基础中的读者monad定义.

它也可能导致严格集合中的性能提升.亦即

data Strict a = Strict !a

instance Functor Strict where
   fmap f (Strict a) = Strict (f a)
   x <$ _ = Strict x
Run Code Online (Sandbox Code Playgroud)

这不符合仿函数法则,但是,在某些情况下,您可能希望这样做.

第三个例子来自无限集合.考虑无限列表

data Long a = Cons a (Long a)

instance Functor Long where
  fmap f (Cons x xs) = Cons (f x) (fmap f xs)
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,但想想

countUpFrom x = Cons x (countUpFrom (x+1))
ones = 1 <$ (countUpFrom 0)
Run Code Online (Sandbox Code Playgroud)

现在,我们的定义将扩展到

ones = 1 <$ (countUpFrom 0)
   = fmap (const 1) (countUpFrom 0) 
   = Cons (const 1 0) (fmap (const 1) (countUpFrom 1)
   = Cons (const 1 0) (Cons (const 1 1) (fmap (const 1) (countUpFrom 2))
Run Code Online (Sandbox Code Playgroud)

也就是说,Cons当你走这个列表时,它将分配一大堆单元格.而另一方面,如果你定义了

x <$ _ = let xs = Cons x xs in xs
Run Code Online (Sandbox Code Playgroud)

ones = 1 <$ countUpFrom 0
 = let xs = Cons 1 xs in xs
Run Code Online (Sandbox Code Playgroud)

这已经打结了.一个更极端的例子是无限的树木

data ITree a = ITree a (ITree a) (ITree a)
Run Code Online (Sandbox Code Playgroud)


Rom*_*aka 9

另一个<$用法示例:

假设你有一个解析器仿函数P,并且parser :: P A.

f <$> parser表示您需要解析某些内容然后应用于f结果.

a <$ parser意味着你不需要解析任何东西(你对结果不感兴趣) - 你只需要识别,这可以更快.

请参阅例如regex-applicative库(注意Void构造函数的用法).