作为应用程序的函数示例,在foldMap和过滤器中可折叠

时间:2017-06-13 02:19:12

标签: haskell applicative

在第一个大块中,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。然而它的工作和类型检查 - 为什么?

3 个答案:

答案 0 :(得分:3)

(<*>)使用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))

......这清楚地说明了发生了什么。

答案 1 :(得分:0)

<*>使用Applicative instance for functions

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

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

替换,<*>的第一个参数变为来自r域和a域的函数,然后返回b ( 2个参数的函数,因为类型r - &gt;(a - &gt; b)等价于r - &gt; a - &gt; b),第二个参数变为r函数域名返回a

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

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

这使我得到一个后续问题/评论,以便将焦点转移到foldMap和filterF,我现在重命名filterH

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

其中h 任何应用程序和monoid具有相应的pure和mempty但尚未定义。所以我需要请求一个返回类型,例如::[Int],以便编译和评估。可以使用filterH而无需指定我自己的类型h吗?我在这个解决方案中遗漏了什么吗?

这是来自可折叠部分的教科书“来自第一原理的哈斯克尔编程”的问题。

答案 2 :(得分:0)

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

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,您可以在其中提供条件,真实情况和else情况的功能。