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