简体   繁体   English

Haskell:f :: hex String - >使用尾递归的整数

[英]Haskell: f :: hex String -> Integer using tail recursion

I'm looking for a way to change hex to an integer using tail recursion. 我正在寻找一种使用尾递归将十六进制更改为整数的方法。 So far I've only tried terrible implementations of regular primitive recursion and I haven't even gotten close. 到目前为止,我只尝试了常规原始递归的可怕实现,我甚至没有接近。 Very frustrated. 非常沮丧。 Even examples of tail recursion will help and be greatly appreciated. 甚至尾递归的例子也会有所帮助并且非常感激。 I don't quite understand it well enough for this implementation. 我对这个实现不太了解它。

Example: 例:

  • "005" -> 5
  • "1E" -> 30

Restrictions: Cannot use imports or if, then, else etc, must be done with recursion if possible or tail recursion. 限制:如果可能或尾递归,不能使用import或if,then,else等必须使用递归。

My attempt at recursion. 我尝试递归。

    hexToInteger :: String -> Integer
        |(x:xs) = []        = []
        |x == 0             = hexToInteger xs
        |otherwise          = addition x + hexToInteger xs

    addition :: String -> Integer
    addition x 
        |--something to check what position we're dealing with and what hex value.
        |--Return the Integer value

Generally, for tail-recursive functions, you need an accumulator argument -- with purity, the result could otherwise only depend on the base case reached. 通常,对于尾递归函数,您需要一个累加器参数 - 具有纯度,否则结果只能取决于达到的基本情况。 So you would need a helper function taking also an accumulator argument, and call that with an initial value for the accumulator, 所以你需要一个辅助函数,也需要一个累加器参数,并用累加器的初始值调用它,

hexToInteger :: String -> Integer
hexToInteger string = hexToIntegerHelper initialAccumulator string

and you must find out 你必须找到答案

  • what initial value you should pass for the accumulator 你应该为累加器传递什么初始值
  • how the accumulator has to be updated in each step. 如何在每个步骤中更新累加器。

For example, a tail-recursive implementation of reverse is 例如, reverse的尾递归实现是

reverse :: [a] -> [a]
reverse xs = reverseHelper [] xs

reverseHelper :: [a] -> [a] -> [a]
reverseHelper accumulator [] = accumulator
reverseHelper accumulator (x:xs) = reverseHelper (x:accumulator) xs

and a tail-recursive factorial (fudging the case of a negative argument) 和一个尾递归因子(捏造负面论证的情况)

factorial :: Integer -> Integer
factorial n = factorialHelper 1 n

factorialHelper :: Integer -> Integer -> Integer
factorialHelper accumulator n
    | n < 2     = accumulator
    | otherwise = factorialHelper (n*accumulator) (n-1)

So you can see the general structure of hexToIntegerHelper , 所以你可以看到hexToIntegerHelper的一般结构,

hexToIntegerHelper :: Integer -> String -> Integer
hexToIntegerHelper accumulator "" = accumulator
hexToIntegerHelper accumulator (d:ds) = hexToIntegerHelper (newAccumulatorFrom accumulator d) ds

and the question is how the new accumulator is to be computed from the old one and the hexadecimal digit (and what the initial accumulator should be). 问题是如何从旧的累加器和十六进制数字(以及初始累加器应该是什么)计算新的累加器。

For the updating of the accumulator, 为了更新累加器,

digitToInt :: Char -> Int

from Data.Char could be useful, that handles all hexadecimal digits. 来自Data.Char可能很有用,它可以处理所有十六进制数字。 But, it doesn't return the desired type, so you'd need to use a fromIntegral or a toInteger to convert the Int to Integer . 但是,它不会返回所需的类型,因此您需要使用fromIntegraltoIntegerInt转换为Integer

Here are two recursive functions, although it has been pointed out to me that they are not tail recursive. 这里有两个递归函数,虽然已经向我指出它们不是尾递归的。 Maybe they can help you get there, though. 也许他们可以帮助你实现目标。

hexToInteger :: String -> Integer
hexToInteger [] = 0
hexToInteger str = 
  fromIntegral z + 16 * hexToInteger (init str)
    where z = let y = last str 
              in if y >= 'A' && y <= 'Z' 
                    then fromEnum y - 55 
                    else if y >= 'a' && y <= 'z'
                            then fromEnum y - 87
                            else fromEnum y - 48



hexToInteger :: String -> Integer
hexToInteger [] = 0
hexToInteger str = 
  z + 16 * hexToInteger (init str)
    where z = case last str of 
                '0' -> 0 
                '1' -> 1 
                '2' -> 2 
                '3' -> 3 
                '4' -> 4 
                '5' -> 5 
                '6' -> 6 
                '7' -> 7 
                '8' -> 8 
                '9' -> 9 
                'A' -> 10 
                'B' -> 11 
                'C' -> 12 
                'D' -> 13 
                'E' -> 14 
                'F' -> 15
                'a' -> 10 
                'b' -> 11 
                'c' -> 12 
                'd' -> 13 
                'e' -> 14 
                'f' -> 15
                otherwise -> 0

We can implement this the same way you would convert a hexadecimal string on paper: Initialize your output to 0, then read the string from left to right, each time multiplying your result by 16 and adding the new digit. 我们可以像在纸上转换十六进制字符串一样实现这一点:将输出初始化为0,然后从左到右读取字符串,每次将结果乘以16并添加新数字。

Create and call a private function with an accumulator argument initialized to 0: 使用初始化为0的累加器参数创建并调用私有函数:

hex2int s = hex2int' s 0
    where

The base case of the recursion takes an empty string and returns the accumulator: 递归的基本情况采用空字符串并返回累加器:

        hex2int' "" n = n

The recursive case takes the first character of the string and increases the accumulator accordingly. 递归情况采用字符串的第一个字符并相应地增加累加器。

        hex2int' (c:s) n = hex2int' s ((n * 16) + (hexDigit2int c))

hexDigit2int is a simple lookup. hexDigit2int是一个简单的查找。

        hexDigit2int c
          | c == "0" = 0

         ...

          | c == "f" = 15

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM