我读了很多关于违禁品的文章,发现https://hackage.haskell.org/package/contravariant-1.4.1/docs/Data-Functor-Contravariant.html#g:3是最好的。
无论如何,我发现,如何使用例如:
*Lib Data.Functor.Contravariant> a = Predicate (\x -> x > 20)
*Lib Data.Functor.Contravariant> :t contramap
contramap :: Contravariant f => (a -> b) -> f b -> f a
*Lib Data.Functor.Contravariant> :t contramap (\x -> x * 2)
contramap (\x -> x * 2) :: (Num b, Contravariant f) => f b -> f b
*Lib Data.Functor.Contravariant> :t contramap (\x -> x * 2) a
contramap (\x -> x * 2) a :: (Ord b, Num b) => Predicate b
*Lib Data.Functor.Contravariant> x = contramap (\x -> x * 2) a
*Lib Data.Functor.Contravariant> getPredicate x 45
True 但却找不出,哪里可以有用。
在我上面发布的网站上,上面写着:
在Haskell中,人们可以认为函子包含或产生值,相反的函子是可以被认为是消费价值的函子。
请看函子的定义:
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b它使用a类型的值,并生成b类型的值。在contramap上,它消耗了这个值。
class Contravariant (f :: * -> *) where
contramap :: (a -> b) -> f b -> f a它使用哪种变量类型的a或b?
https://www.fpcomplete.com/blog/2016/11/covariance-contravariance也有一个关于正负位置的问题。网站上写着:
查看违禁品类型定义:
contramap :: (a -> b) -> f b -> f a作者指向哪个类型的变量?
发布于 2018-02-02 17:15:31
函子f被认为是“包含”或“生成”值,因为f a就像a值的容器。fmap允许您转换f所持有的值。
示例:
[a]‘包含一个非负数的a类型值。IO a可能会执行一些IO和“返回”或“生成”a类型的值。(->) r a‘包含一个a类型的值,用于r的每个值现在,Contravariant f是一种可以“接受”或“消费”价值的东西。contramap允许您转换f a在消耗它们之前获取的东西。
这方面的主要示例通常是使用以下内容
newtype Op r a = Op { runOp :: a -> r }
(请注意,您使用的Predicate似乎只是Op Bool)
现在,我们有了一些可以“消费”a类型值的东西。(这个类比对于Op (IO ())来说可能更有意义)
继续这个“消耗”值的例子,考虑o = Op (\x -> putStrLn x) :: Op (IO ()) String,现在如果我们想要使用o,但是对于Show a => a类型的值呢?这就是contramap的目的!
contramap show o :: Show a => Op (IO ()) a
(注意,在这个简单的例子中,runOp (contramap show o)只是print)
编辑:
关于Contravariant的另一件有趣的事情是关于它的组成。
给定Contravariant c, Contravariant d, Functor f和
newtype Compose f g a = Compose { runCompose :: f (g a) }
我们有:
Compose f c也是Contravariant
contramap f (Compose fca) = Compose $ fmap (contramap f) fcaCompose c f也是Contravariant
contramap f (Compose cfa) = Compose $ contramap (fmap f) cfaCompose c d实际上是一个Functor
fmap f (Compose cda) = Compose $ contramap (contramap f) cda发布于 2022-07-05 17:52:47
首先,看看签名,一切都在那里。
第二,如果你想“感觉”这些事情,考虑一下函子,试着用语言表达他们所做的事情。
函子用其包含的类型做某事。这可以是一种消费,也可以是这类产品的生产。一个列表,清楚地“生成”类型的实例。显然,打印机“消耗”类型的实例。
当给定一个函数时,生产者构建一个函数来转换生产“后”。从一个简单的函数中,您可以在生产之后应用函数域获得一个生产者。fmap的签名是“协变”的。
当给定一个函数时,消费者会构建一个函数来转换“以前”的消费。通过提供从int到string的转换器函数,已经持有字符串使用者的使用者将很容易地生成int的使用者:在消费前应用该函数。违禁品的签名是“反变体”。
我们可以说,功能“转换”,而函子“消费”或“生产”。
https://stackoverflow.com/questions/48587361
复制相似问题