在Haskell中将基数为3的数字列表转换为相应的数值

时间:2014-11-10 14:07:44

标签: haskell recursion

下面我定义了一个函数,它将base-3数字列表转换为相应的数值。例如:

f "201" = (2 * 3^2) + (0 * 3^1) + (1 * 3^0) = 19
f "12" = 5
f "1202" = 47
f "120221" = 430

这是一个使用理解的定义:

f :: String -> Int
f str = sum (listToFinal (stringToTuples str))

助手功能:

- 1)转换" 201"到" 102"

reverse "str"

- 2)转换" 102"到102

stringToInt :: String -> Int
stringToInt str = read str :: Int

- 3)将102转换为[' 1',' 0',' 2']

intToList :: Int -> [Int]
intToList 0 = []
intToList x = intToList (x `div` 10) ++ [x `mod` 10]

- 4)转换" 201"到[(1,0),(0,1),(2,2)]使用reverse,stringToInt,intToList

stringToTuples :: String -> [(Int,Int)]
stringToTuples str = zip (intToList (stringToInt (reverse str))) [0..]

- 5)将[(1,0),(0,1),(2,2)]转换为[1 * 3 ^ 0,0 * 3 ^ 1,2 * 3 ^ 2]

listToFinal :: [(Int,Int)] -> [Int]
listToFinal list = [ x * (3^y) | (x,y) <- list ]

现在我只想用递归来做(当然,使用基本和库函数)。

一个想法:我正在考虑将列表中的每个元素的头部简单地乘以3 ^(字符串的长度-1)。唯一的问题是,每次递归调用时,三次幂必须减少1,例如给出:

recursive_version "201" = (2 * 3^2) + (0 * 3^1) + (1 * 3^0)

如何实现?

2 个答案:

答案 0 :(得分:1)

这是一种更简单的方法;请注意,通过使用foldl,它只是“隐式”递归。有关信息,digitToInt将导出Data.Char

import Data.Char
import Data.List ( foldl' )

--- horner x xs : the value of polynomial 'xs' at point 'x'
horner :: Int -> [Int] -> Int
horner x = foldl' (\c1 c0 -> c1 * x + c0) 0

-- f s : the integer whose representation in base 3 is string 's'
f :: String -> Int
f = horner 3 . map digitToInt

答案 1 :(得分:0)

当你递归地定义它时,减少长度的自然方法是从头部修剪数组。例如:

base3 x = base3' x 0 where
  base3' (d:ds) v = base3' ds $ v + d * 3 ^ length ds
  base3' [] v = v