繁体   English   中英

Haskell中的“双重”功能组合

[英]“Double” function composition in Haskell

我从编译器的建议中发现了一些对我来说很奇怪的东西。

我做了一个数据类型来表示二进制数字,如下所示:

data Bin = Zero | One

我选择将多位二进制数表示为Bin类型的列表,如下所示:

myNum :: [Bin]
myNum = [One, Zero, One, One] -- represents the number 1011

自然地,我想以一种更方便的方式显示我的二进制数,所以我创建了一个Show实例来为我做这件事:

instance Show Bin where
    show Zero = "0"
    show One  = "1"
    showList []     = showString ""
    showList (x:xs) = showString (show x) . showList xs

print myNum ,并且print myNum正确显示1011

我在Haskell还是很新,这是我第一次使用showList。 但这对我来说很有意义。 由于showList的类型为[a] -> ShowS (它本身是[a] -> (String -> String)的别名),因此我了解到我是通过使用函数组合来“串联”列表的元素的。 但是编译器建议我使用showList函数并重新定义它:

Warning: Use foldr
  Found:
    showList [] = showString ""
    showList (x : xs) = showString (show x) . showList xs
  Why not:
    showList xs = foldr ((.) . showString . show) (showString "") xs

而且,一旦我替换了它的建议,它便提出了进一步的建议:

Error: Eta reduce
  Found:
    showList xs = foldr ((.) . showString . show) (showString "") xs
  Why not:
    showList = foldr ((.) . showString . show) (showString "")

我了解Eta减少错误,因为通常最好编写无点函数。 但是我在第一次转换时遇到了麻烦。 我看到foldr的第二个参数是“基本情况”正确的身份,但是我很难理解foldr的第一个参数中发生了什么。 所以我有两个问题:

  1. 如何重写((.) . showString . show) 例如,我知道(f . g) x可以重写为f (gx)
  2. 这实际上在文件foldr的上下文中有什么作用?

如何重写它,如下所示,首先让我们将合成模式分解为一个单独的函数

 compose :: [a -> a] -> a -> a
 compose = foldr (.) id

您可以将其可视化为获取列表f : g : h : []并将[]替换为id: . 给你留下f . g . h . id f . g . h . id f . g . h . idf . g . h f . g . h f . g . h

接下来,让我们用它来重写您的示例,使其更清晰易读

  instance Show Bin where
    showList = compose . map (showString . show)

现在,尽管功能相同,但它比您现在的要清晰一些。 实际上,由于GHC可能将其融合(?),因此甚至可能以相同的方式编译。 我们将每个项目转换为ShowS String -> StringShowS ,然后将它们全部组成。 提供名称和类型来compose ,可以更轻松地了解正在发生的事情。

我想这也可以写成

 showList = appEndo . mconcat . map (Endo . showString . show)

这与上面的相同,但是依赖于以下事实: mconcat a -> a形成一个monoid,而mconcat推广了将一个monoid列表组合为一个的想法。 我们需要Endo位,因为实际上为

newtype Endo a = End {appEndo :: a -> a}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM