我试图实现一个具有lens
参数的函数,并且mconcat
Maybe
一个(->) r
幺半群具有z pom root [(textFrom "groupId"), (textFrom "artifactId"), (textFrom "version")]
textFrom :: Text -> Document -> Lens' Document Element -> Maybe Text
textFrom name pom ln = listToMaybe $ pom ^.. ln ./ ell name . text
类型的两个应用效果。我可能遗漏了一些基础知识,所以对分解这个问题的任何帮助表示赞赏。
我想写'用户'避免传递相同参数的代码,如下所示:
Prelude Data.Monoid Control.Applicative> let f a b = Just $ show (a+1) ++ b
Prelude Data.Monoid Control.Applicative> let z a b xs = mconcat $ ($ b) <$> ($ a) <$> xs
Prelude Data.Monoid Control.Applicative> z 3 "x" [f,f]
Just "4x4x"
这是我尝试过的。没有镜头的概念:
z :: (forall f. Functor f, Monoid b) => Document -> ((Element -> f Element) -> Document -> f Document) -> [Document -> ((Element -> f Element) -> Document -> f Document) -> b] -> b
z pom ln xs = mconcat $ ($ ln) <$> ($ pom) <$> xs
带镜头:
Couldn't match expected type ‘[a0
-> Document
-> [Document
-> ((Element -> f Element) -> Document -> f Document) -> b]
-> b]’
with actual type ‘(Element -> f Element) -> Document -> f Document’
Relevant bindings include
xs :: (Element -> f Element) -> Document -> f Document
(bound at Main.hs:27:10)
z :: (forall (f1 :: * -> *). Functor f1)
-> Monoid b =>
Document
-> ((Element -> f Element) -> Document -> f Document)
-> [Document
-> ((Element -> f Element) -> Document -> f Document) -> b]
-> b
(bound at Main.hs:27:1)
Probable cause: ‘xs’ is applied to too few arguments
In the second argument of ‘(<$>)’, namely ‘xs’
In the second argument of ‘($)’, namely ‘($ ln) <$> ($ pom) <$> xs’
但它无法编译:
{{1}}
答案 0 :(得分:2)
有时,将镜头存放在容器中会导致问题,但我们可以使用ALens'
来规避这些问题。从概念上讲,ALens' Element Document
与Functor f => ((Element -> f Element) -> Document -> f Document)
或多或少相同,但您可以将其放入容器中,问题较少。需要注意的一点是,每个镜头都是普遍适用于所有Functor
的镜头,因此原始签名实际上看起来应该更像这样(虽然这不太合适):</ p>
z :: (Monoid b)
=> Document
-> (forall f. Functor f => (Element -> f Element) -> Document -> f Document)
-> [Document -> (forall f. Functor f => (Element -> f Element) -> Document -> f Document) -> b]
-> b
如果我们使用z
给ALens'
一个类型,我们最终得到这个(假设您正在使用lens
库。如果没有,请参阅底部的注释):< / p>
z :: (Monoid b)
=> Document
-> ALens' Element Document
-> [Document -> ALens' Element Document -> b]
使用这个新签名,您提供的原始定义将起作用。
我们可以使用不同的Monoid
实例来简化此定义。 Monoid b => (a -> b)
Monoid
实例组合了具有Monoid
结果类型的函数。这是一个例子:
lengthSum :: [a] -> Sum Int
lengthSum xs = Sum (length xs)
λ> (lengthSum <> lengthSum) "abc"
Sum {getSum = 6}
(<>)
方法mappend
是将每个函数应用于给定参数的结果(因此它最终与length "abc" + length "abc"
基本相同)。同样,mconcat
将组合函数列表的结果。这也扩展到多个参数的函数,只要每个函数是相同的类型,结果类型是Monoid
的实例。
有了这个实例,我们可以定义:
z pom ln xs = mconcat xs pom ln
此定义适用于该类型的镜头和非镜头版本。
如果您没有使用lens
库,则应该可以将ALens'
定义为
newtype ALens s t a b = ALens
{ getLens :: forall f. Functor f => (a -> f b) -> s -> f t
}
type ALens' s a = ALens s s a a