我正在玩.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)
这很好用。所以问题是我根本不知道如何在操作其中的列表时返回单个元组。它真的让我烦恼,任何人都可以帮忙吗?
答案 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
,则不会触发任何函数调用。