为什么在Haskell中尝试从十六进制转换为十进制时会得到错误的结果?

为什么在Haskell中尝试从十六进制转换为十进制时会得到错误的结果?,haskell,recursion,Haskell,Recursion,已解决 我的功能不能正常工作。当我执行hex2dec“100”或“10000”时,它给出的是16,而不是正确的256。当我做hex2dec“101”时,它给出的是17,而不是正确的257 hex2dec :: String -> Integer hex2dec str = go (reverse str) where go [] = 0 go (x:xs) = hexChar x + 16 * hex2dec xs hexChar :: Cha

已解决

我的功能不能正常工作。当我执行hex2dec“100”或“10000”时,它给出的是16,而不是正确的256。当我做hex2dec“101”时,它给出的是17,而不是正确的257

hex2dec :: String -> Integer
hex2dec str = go (reverse str)
      where go []     = 0
            go (x:xs) = hexChar x + 16 * hex2dec xs

hexChar :: Char -> Integer
hexChar c
      | c == '0' = 0
      | c == '1' = 1
      | c == '2' = 2
      | c == '3' = 3
      | c == '4' = 4
      | c == '5' = 5
      | c == '6' = 6
      | c == '7' = 7
      | c == '8' = 8
      | c == '9' = 9
      | c == 'a' = 10
      | c == 'b' = 11
      | c == 'c' = 12
      | c == 'd' = 13
      | c == 'e' = 14
      | c == 'f' = 15
      | otherwise     = 0
我不得不把“hex2dec”改成“go”


注意你的函数是局部的;并非所有的
Char
值都是有效的十六进制数字。相反,请定义一个新类型来表示它们:

data Hex = H0 | H1 | H2 | H3
         | H4 | H5 | H6 | H7
         | H8 | H9 | HA | HB
         | HC | HD | HE | HF deriving (Enum)
派生一个
Enum
实例几乎免费为您提供
hexChar
(我们称之为
hexInt
);我们在这里从
Int
切换到
Integer

hexInt :: Hex -> Integer
hexInt = fromIntegral . fromEnum
有了它,您可以使用霍纳规则将
Hex
值列表减少为
整数

hex2dec :: [Hex] -> Integer
hex2dec = foldr (\d acc -> hexInt d + 16*acc) 0

为了将其从
[Hex]
推广到
字符串
,我们首先定义一个函数,将
字符
转换为
可能是十六进制

import Data.List

charToHex :: Char -> Maybe Hex
charToHex c = fmap toEnum $ c `elemIndex` "0123456789abcdef"
-- elemIndex returns a Maybe Int "between" Just 0 and Just 15;
-- fmap toEnum converts that to a Maybe Hex.
如果你想表达得更清楚,
charToHex
当然很简单

charToHex '0' = Just H0
-- ...
charToHex 'f' = Just H15
charToHex _ = Nothing
然后我们需要一个函数,它可以在映射
charToHex
String
时处理任何故障

str2dec :: String -> Maybe Integer
str2dec = fmap hex2dec . traverse charToHex

其中
transverse charToHex::String->Maybe[Hex]
返回
Nothing
如果对输入字符串上的
charToHex
进行任何调用都返回
Nothing

为了避免调用
reverse
,请尝试使用累加器使用尾部递归来编写它-例如@ErikR得到了它。谢谢你的主意。hex2dec acc[]=acc hex2dec acc(x:xs)=hex2dec(acc*16+hexChar x)xsTips:查看
Data.List.findIndex
,了解编写
hexChar
的更好方法。如果这不是练习,还有
Numeric.readHex
。谢谢。是的,这不是一个练习。只是一个代码版本的挑战。。。。那些不是练习吗?
str2dec :: String -> Maybe Integer
str2dec = fmap hex2dec . traverse charToHex