求助:如何用非递归方式实现Haskell十进制转八进制函数
非递归实现十进制Int转八进制(Haskell)
方法1:用unfoldr生成余数序列
unfoldr是Haskell里生成列表的非递归工具,刚好适配这种逐步分解数值的场景:
import Data.List (unfoldr) decimalToOctal :: Int -> String decimalToOctal 0 = "0" decimalToOctal n = reverse $ map (head . show) $ unfoldr step (abs n) where step 0 = Nothing step x = Just (x `mod` 8, x `div` 8)
unfoldr step (abs n)会反复调用step,每次返回当前值模8的结果,以及更新后的被除数(当前值除以8),直到被除数为0,生成的余数列表是低位到高位的顺序(比如十进制10会生成[2,1])- 用
reverse反转列表得到正确的高位到低位顺序 map (head . show)把每个Int类型的余数转换为字符
方法2:用iterate生成中间值再提取余数
如果不想用unfoldr,可以通过iterate生成所有除以8的中间结果,再过滤提取余数:
decimalToOctal :: Int -> String decimalToOctal 0 = "0" decimalToOctal n = reverse $ map (`mod` 8) $ takeWhile (/=0) $ iterate (`div`8) (abs n)
iterate (div8) (abs n)生成序列:n, ndiv8, ndiv8div8,...直到出现0takeWhile (/=0)截取到0之前的所有中间值map (mod8)给每个中间值取模8得到余数列表,反转后转成字符串即可
针对你提到的foldr的补充
你之前想用foldr累积单一值的思路不太适配,但可以先生成余数序列,再用foldr拼接成最终字符串:
decimalToOctal :: Int -> String decimalToOctal 0 = "0" decimalToOctal n = foldr (\d acc -> show d ++ acc) "" $ reverse remainders where remainders = unfoldr step (abs n) step 0 = Nothing step x = Just (x `mod`8, x`div`8)
注:以上函数处理了0和负数的情况(取绝对值转换),如果只需要处理正整数,可去掉abs。
内容的提问来源于stack exchange,提问作者J. G.
相关产品推荐
相关产品推荐

