【问题标题】:Haskell return single tuple after recursionHaskell 在递归后返回单个元组
【发布时间】:2014-04-02 04:22:00
【问题描述】:

我在玩 .bmp 图像和 ascii 艺术,遇到了关于模式匹配和元组递归的问题。

该函数需要简单地将单词列表转换为整数。同时携带高度和宽度不变。我的尝试:

convertToIntegers :: ([GHC.Word.Word8], Integer, Integer) -> ([Integer], Integer, Integer)
convertToIntegers ([], x, y) =  ([], x, y)
convertToIntegers ((a:as), x, y) = ( toInteger a : convertToIntegers (as, x, y), x, y)

显然,这不起作用并返回类型错误:

Couldn't match expected type `[Integer]' with actual type `([Integer], Integer, Integer)'

In the return type of a call of `convertToIntegers' 
In the second argument of `(:)', namely `convertToIntegers (as, x, y)'
In the expression: toInteger a : convertToIntegers (as, x, y)

看起来应该很简单,我可以通过拆分它并使用辅助函数来完成它。为了弄清楚这一点,我尝试了以下方法:

convertToIntegers :: ([GHC.Word.Word8], Int, Int) -> [Integer]
convertToIntegers ([], x, y) =  []
convertToIntegers ((a:as), x, y) = toInteger a : convertToIntegers (as, x, y)

这很好用。所以问题是我根本不知道如何在操作其中的列表时返回单个元组。真是烦死我了,谁能帮忙?

【问题讨论】:

    标签: haskell recursion tuples


    【解决方案1】:

    编码这种使用模式的标准方法是使用let

    convertToIntegers :: ([GHC.Word.Word8], Integer, Integer) -> ([Integer], Integer, Integer)
    convertToIntegers ([], x, y) =  ([], x, y)
    convertToIntegers ((a:as), x, y) = let (rs, x2, y2) = convertToIntegers (as, x, y)
                                       in  (toInteger a : rs, x2, y2)
    

    Haskell 的let 是递归的;如果您在let 内定义的两侧使用x,y,您将隐藏外部名称x,y(阻止对它们的访问)。这样,等式右侧的x,y 引用外部参数x,y,左侧的x2,y2 用于传递从内部函数调用返回的值。

    这并不意味着在返回值之前进行了此调用。恰恰相反,由于 Haskell 的惰性,首先构造返回值(一个三元组),带有孔,(_1, _2, _3),只有当这些孔将被访问时,才会根据定义触发进一步的评估,_1 = toInteger a : rs_2 = x2_3 = y2。因此,如果该访问权限为head _1,则不会触发任何函数调用。

    【讨论】:

      【解决方案2】:

      为什么不只使用地图?

      convertToIntegers :: ([GHC.Word.Word8], Integer, Integer) -> ([Integer], Integer, Integer)
      convertToIntegers (as, x, y) = (map toInteger as, x, y)
      

      编辑:

      您的主要问题是这里有一个实际的错误:

      ( toInteger a : convertToIntegers (as, x, y), x, y)
                                          ^  ^  ^
      

      您正在返回一个元组作为另一个元组的第一个参数,在您声称要返回整数列表的类型签名中。如果你不想使用地图,你可以这样写:

      convertToIntegers :: ([GHC.Word.Word8], Integer, Integer) -> ([Integer], Integer, Integer)
      convertToIntegers (as, x, y) = (convertWords as, x, y)
          where
              convertWords [] = []
              convertWords (z:zs) = toInteger z : convertWords zs
      

      【讨论】:

      • 哇,我不知道你可以在 where 子句中进行多个模式匹配,谢谢!
      猜你喜欢
      • 2019-03-19
      • 2013-12-05
      • 2016-01-25
      • 2016-01-24
      • 2018-02-20
      • 1970-01-01
      • 2021-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多