Haskell在递归后返回单个元组

时间:2014-02-28 23:02:28

标签: haskell recursion tuples

我正在玩.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)

这很好用。所以问题是我根本不知道如何在操作其中的列表时返回单个元组。它真的让我烦恼,任何人都可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

为什么不直接使用地图?

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)
                                    ^  ^  ^

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

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

答案 1 :(得分: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是递归的;如果您在x,y内的定义的两边使用let,则会隐藏外部名称x,y(阻止对它们的访问)。这样,等式的RHS上的x,y引用外部参数x,y,并且LHS上的x2,y2用于传递内部函数调用返回的值。

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