“Const”应用函子有什么用途?

30

我刚在Control.Applicative的文档中发现了Const,但是我很难理解它在哪些情况下有用,相比直接使用Monoid

我错过了什么吗?

4个回答

28

Traversable结合使用时非常有用。

getConst . traverse Const :: (Monoid a, Traversable f) => f a -> a

这就是将一堆东西黏在一起的通用方法。这是我被说服将 Applicative Monad 分开的用例之一。我需要像广义的 elem 这样的东西。

elem :: Eq x => x -> Term x -> Bool

我希望为一个参数化自由变量表示的可遍历术语(Traversable Term)执行出现检查。我一直在更改Term的表示方式,厌倦了修改无数个遍历函数,其中一些是进行累加而不是有副作用的映射。我很高兴找到了一种同时涵盖这两个方面的抽象。


http://www.soi.city.ac.uk/~ross/papers/Applicative.html 的第4节是遍历技巧的好参考。 - Daniel
foldMap id 不会产生更少的约束(使用 Foldable 而不是 Traversable),但会产生相同的结果吗? - Petr
1
的确,这就是为什么Foldable存在的原因。但是,一切Traversable都是Foldable,这非常有用,上面是foldMapDefault的构造方式。插播一句:SHE支持DefaultSuperclassInstances,因此通过默认静默方式,一切Traversable都变成了Foldable - pigworker
这也可以写成:(^. traverse)。对于许多人来说显而易见,但对于像我这样不总能轻松阅读这些表达式的人来说可能很有用。 - Paul Gardiner

7

正如dave4420所提到的,实现Van Laarhoven lens的访问器和更新器涉及到Const函子。更详细地说:

{-# LANGUAGE Rank2Types #-}

import Control.Applicative
import Control.Monad.Identity

-- The definition of Van Laarhoven lenses:
type Lens a b = forall f . Functor f => (b -> f b) -> (a -> f a)

-- Getter passes the Const functor to the lens:
get :: Lens a b -> a -> b
get l = getConst . (l Const)

-- Updater passes the Identity functor to the lens:
modify :: Lens a b -> (b -> b) -> (a -> a)
modify l f = runIdentity . l (Identity . f)

set :: Lens a b -> b -> (a -> a)
set l r = modify l (const r)

-- Example: -------------------------------------------

data Person = Person { _name :: String, _age :: Int }
  deriving Show

name :: Lens Person String
name f (Person n a) = fmap (\x -> Person x a) (f n)

age :: Lens Person Int
age f (Person n a) = fmap (\x -> Person n x) (f a)

main :: IO ()
main = do
    let john = Person "John" 34
    print $ get age john
    print $ set name "Pete" john

7

当你拥有适用于所有(Applicative)Functor的函数或数据结构,并希望以退化的方式重复使用它时,这将非常有用。这类似于向可以接受任意函数的函数传递constid

Van Laarhoven镜头是基于任意Functor定义的,并使用Const来派生字段访问器(以及同样简单的Identity来派生字段更新器)。

Traversable类型,如pigworker所提到的,就是另一个例子。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接