作为应用程序的函数示例,在 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
其中 h
是 any 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,您可以在其中为条件、真实情况和其他情况提供功能。
在第一个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
其中 h
是 any 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,您可以在其中为条件、真实情况和其他情况提供功能。