[英]“Double” function composition in Haskell
I came across something that seems very strange to me, coming from the compiler's suggestions. 我从编译器的建议中发现了一些对我来说很奇怪的东西。
I made a data type to represent binary numbers as follows: 我做了一个数据类型来表示二进制数字,如下所示:
data Bin = Zero | One
I chose to represent multiple-digit binary numbers as lists of type Bin, like so: 我选择将多位二进制数表示为Bin类型的列表,如下所示:
myNum :: [Bin]
myNum = [One, Zero, One, One] -- represents the number 1011
Naturally, I want to display my binary numbers in a more convenient way, so I made an instance of Show to do this for me: 自然地,我想以一种更方便的方式显示我的二进制数,所以我创建了一个Show实例来为我做这件事:
instance Show Bin where
show Zero = "0"
show One = "1"
showList [] = showString ""
showList (x:xs) = showString (show x) . showList xs
This works, and print myNum
correctly displays 1011
. 这
print myNum
,并且print myNum
正确显示1011
。
I'm still fairly new at Haskell, and this is my first time working with showList. 我在Haskell还是很新,这是我第一次使用showList。 But this makes sense to me.
但这对我来说很有意义。 Since showList has type
[a] -> ShowS
(which is itself an alias for [a] -> (String -> String)
), I understand that I "concatenate" the elements of a list by using function composition. 由于showList的类型为
[a] -> ShowS
(它本身是[a] -> (String -> String)
的别名),因此我了解到我是通过使用函数组合来“串联”列表的元素的。 But the compiler suggested that I take the showList function and redefine it: 但是编译器建议我使用showList函数并重新定义它:
Warning: Use foldr
Found:
showList [] = showString ""
showList (x : xs) = showString (show x) . showList xs
Why not:
showList xs = foldr ((.) . showString . show) (showString "") xs
And, once I had replaced what it suggested, it made a further suggestion: 而且,一旦我替换了它的建议,它便提出了进一步的建议:
Error: Eta reduce
Found:
showList xs = foldr ((.) . showString . show) (showString "") xs
Why not:
showList = foldr ((.) . showString . show) (showString "")
I understand the Eta reduce error, since it's usually preferable to write point-free functions. 我了解Eta减少错误,因为通常最好编写无点函数。 But I'm having trouble with the first conversion.
但是我在第一次转换时遇到了麻烦。 I see that the second argument to
foldr
is the "base case" right identity, but I'm having difficulty understanding what is going on in the first argument to foldr
. 我看到
foldr
的第二个参数是“基本情况”正确的身份,但是我很难理解foldr
的第一个参数中发生了什么。 So I have two questions: 所以我有两个问题:
((.) . showString . show)
? ((.) . showString . show)
? For example, I know that (f . g) x
can be re-written as f (gx)
. (f . g) x
可以重写为f (gx)
。 foldr
? foldr
的上下文中有什么作用? How about rewriting it as follows, first let's break out the pattern of composition into a separate function 如何重写它,如下所示,首先让我们将合成模式分解为一个单独的函数
compose :: [a -> a] -> a -> a
compose = foldr (.) id
You can visualize this as taking a list f : g : h : []
and replacing []
with id
and :
with .
您可以将其可视化为获取列表
f : g : h : []
并将[]
替换为id
和:
.
, leaving you with f . g . h . id
给你留下
f . g . h . id
f . g . h . id
f . g . h . id
or f . g . h
f . g . h . id
或f . g . h
f . g . h
f . g . h
. f . g . h
。
Next let's use this to rewrite your example to make it a bit more legible 接下来,让我们用它来重写您的示例,使其更清晰易读
instance Show Bin where
showList = compose . map (showString . show)
Now this is a bit more legible than what you had even though it's functionally identical. 现在,尽管功能相同,但它比您现在的要清晰一些。 In fact this may end up even compiling as the same thing since GHC may fuse it(?).
实际上,由于GHC可能将其融合(?),因此甚至可能以相同的方式编译。 we're transforming each item into a
String -> String
or ShowS
, and then we're composing them all. 我们将每个项目转换为
ShowS
String -> String
或ShowS
,然后将它们全部组成。 Giving a name and type to compose
makes it much easier to see what's going on. 提供名称和类型来
compose
,可以更轻松地了解正在发生的事情。
I suppose this could also be written 我想这也可以写成
showList = appEndo . mconcat . map (Endo . showString . show)
This is identical to the above but relies on the fact that a -> a
forms a monoid and mconcat
generalizes the idea of combining a list of monoids to one. 这与上面的相同,但是依赖于以下事实:
mconcat
a -> a
形成一个monoid,而mconcat
推广了将一个monoid列表组合为一个的想法。 We need that Endo
bit because the monoid instance is actually defined for 我们需要
Endo
位,因为实际上为
newtype Endo a = End {appEndo :: a -> a}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.