作为应用程序的函数示例,在 foldMap 和 filter for foldables 中

Example of functions as applicatives, in foldMap and filter for foldables

在第一个hunk中,filterF是用foldMap

实现的
import Data.List

pred :: a -> Bool
pred = undefined

wrapperOfA :: (Applicative f, Monoid (f a)) => a -> Bool -> f a 
wrapperOfA a condition = if condition then pure a else mempty

-- foldMap :: (Foldable t, Monoid  f a) => (a -> f a) -> t a -> f a
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a 
filterF pred = foldMap ((<*>) wrapperOfA  pred)
filterF (<3) [5,4,3,2,1] :: [Int]
-- [2,1]

... 它利用了一些 Applicative 的应用函数,又名 <*> 通常是固定的。现在,<*> 的类型是:

:t (<*>)
--(<*>) :: forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b

但是用孔替换它会得到它的类型

-- (a0 -> Bool -> f0 a0) -> (a -> Bool) -> a -> f a
-- namely, from typechecking
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a 
filterF pred = foldMap (_ wrapperOfA pred)
-- Found hole ‘_’ with type: (a0 -> Bool -> f0 a0) -> (a -> Bool) -> a -> f a
-- Where: ‘a’ is a rigid type variable bound by the type signature for interactive:IHaskell136.filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a at :1:12
--       ‘f’ is a rigid type variable bound by the type signature for interactive:IHaskell136.filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a at :1:12
--       ‘a0’ is an ambiguous type variable
--       ‘f0’ is an ambiguous type variable
-- Relevant bindings include
--   pred :: a -> Bool (bound at :2:9)
--   filterF :: (a -> Bool) -> t a -> f a (bound at :2:1)
-- In the expression: _
-- In the first argument of ‘foldMap’, namely ‘(_ wrapperOfA pred)’
-- In the expression: foldMap (_ wrapperOfA pred)

基本上,wrapperOfA 不像 <*> 所暗示的那样 f (a -> b)pred 也不像类型 f a。然而它有效并进行类型检查 - 为什么?

那里的(<*>)用的是Applicative instance for functions。在...

-- Writing it infix, for the sake of clarity. 
filterF pred = foldMap (wrapperOfA <*> pred)

...wrapperOfA 的类型为 a -> (Bool -> f a)pred 的类型为 a -> Bool。既然如此,wrapperOfA <*> pred 的类型就如预期的那样 a -> f a。如果我们用 (<*>) 的实现替换函数(详见上面链接的问题),我们得到...

filterF pred = foldMap (\a -> wrapperOfA a (pred a))

...这让事情变得一目了然。

<*> 使用 Applicative instance for functions

 (<*>) :: f (a -> b) -> f a -> f b

其中 f(->) r ,即来自 r 域的函数。

代入,<*> 的第一个参数变成 来自 r 域和 a 域的函数,然后 returning 一个 b(一个有 2 个参数的函数,因为类型 r -> (a -> b) 等价于 r -> a -> b),第二个参数变为 来自 r 域的函数 returning 一个 a.

要生成 (->) r b,我们应该将第二个参数(函数)应用于 r 参数,并将结果 a 作为第二个参数传递给<*> 前面的东西。也就是说,

(<*>) wrapperOfA pred r = wrapperOfA r (pred r)

这让我进行 跟进 question/comment,将重点放在 foldMap 和 filterF 上,我现在将其重命名为 filterH

    filterH :: (a -> Bool) -> t a -> h a
    foldMap :: (a -> f a) -> t a -> f a
    wrapperOfA <*> pred :: a -> h a

其中 hany applicative and monoid with corresponding pure and mempty 但尚未定义。所以我需要请求一个 return 类型,例如 ::[Int] 以便它编译和评估。 filterH 可以不用指定我自己的类型就可以使用吗h?我在这个解决方案中遗漏了什么吗?

这是教科书 "haskell programming from first principles" 中可折叠部分的问题。

也许您会发现此解决方案更简单:

import Control.Conditional (select)

filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a
filterF f = foldMap (select f pure mempty)

这里,select 只是一个功能性的 if-then-else,您可以在其中为条件、真实情况和其他情况提供功能。