Zub*_*air 6 haskell functor applicative
我在理解(->) rApplicative 的函数实例如何在Haskell中工作时遇到了一些麻烦.
例如,如果我有
(+) <$> (+3) <*> (*100) $ 5
我知道你得到的结果508时,我就明白,你需要的结果(5 + 3)和(5 * 100)你申请的(+)功能,这两种.
但是我不太明白发生了什么.我假设表达式括号如下:
((+) <$> (+3)) <*> (*100)
根据我的理解,正在发生的事情是您(+)对最终结果的映射(+3),然后您正在使用<*>运算符将该函数应用于最终结果(*100)
但是我不明白的实施<*>为(->) r实例,我为什么不能写:
(+3) <*> (*100)
怎样的<*>,<$>当它涉及到运营商的工作(->) r?
<$>只是另一个名字fmap和它的定义(->) r是(.)(复合算):
intance Functor ((->) r) where
  fmap f g = f . g
<*>通过查看类型,您基本上可以完成实现:
instance Applicative ((->) r) where
  (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
  f <*> g = \x -> f x (g x)
你有一个函数from rto ato b和一个函数from rto a.你想从funtion r到b结果.你知道的第一件事是你返回一个函数:
\x ->
现在你要申请,f因为它是唯一可以返回的项目b:
\x -> f _ _
现在的论点f是类型r和a.r很简单x(因为它是alrady的类型r,你可以a通过申请g获得x:
\x -> f x (g x)
Aaand你已经完成了.这是Haskell Prelude中实现的链接.
考虑以下类型的签名<*>:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
将此与普通函数应用程序的类型签名进行比较,$:
($) :: (a -> b) -> a -> b
请注意,它们非常相似!实际上,<*>操作员有效地推广应用程序,以便根据所涉及的类型使其过载.这是很容易用最简单的时候看到Applicative,Identity:
ghci> Identity (+) <*> Identity 1 <*> Identity 2
Identity 3
这也可以通过稍微复杂的应用仿函数来看到,例如Maybe:
ghci> Just (+) <*> Just 1 <*> Just 2
Just 3
ghci> Just (+) <*> Nothing <*> Just 2
Nothing
因为(->) r,Applicative实例执行一种函数组合,它生成一个新函数,它接受一种"上下文"并将其线程化为所有值以生成函数及其参数:
ghci> ((\_ -> (+)) <*> (+ 3) <*> (* 100)) 5
508
在上面的例子中,我只使用了<*>,所以我明确写出第一个参数是忽略它的参数并且总是生成(+).但是,Applicative类型类还包括pure函数,它具有将纯值"提升"为应用函子的相同目的:
ghci> (pure (+) <*> (+ 3) <*> (* 100)) 5
508
但在实践中,你很少会看到pure x <*> y,因为它完全等效于x <$> y由Applicative法律,因为<$>仅仅是一个中缀代名词fmap.因此,我们有一个共同的习语:
ghci> ((+) <$> (+ 3) <*> (* 100)) 5
508
更一般地说,如果您看到任何表达式如下所示:
f <$> a <*> b
... f a b除了在特定Applicative实例的习语的上下文中,您可以或多或少地像普通函数应用程序一样阅读它.实际上,Applicative提出了"成语括号"这一概念的原始表述,它将为上述表达式添加以下语法糖:
(| f a b |)
然而,Haskellers似乎与添加额外语法的好处并没有被认为是值得的成本,所以中缀运营商不够满意<$>,并<*>保持必要的.
| 归档时间: | 
 | 
| 查看次数: | 368 次 | 
| 最近记录: |