【问题标题】:Binary to Decimal Conversion in Haskell using Horners Algorithm使用 Horners 算法在 Haskell 中进行二进制到十进制转换
【发布时间】:2019-02-05 19:15:41
【问题描述】:

我正在尝试在这里实现一个函数,该函数接受一个表示二进制数的 Bool 列表,例如 [True, False, False],并根据 Horners 方法将其转换为相应的十进制数。

函数类型为[Bool] -> Int

我关注的算法是:

Horners 算法视觉解说:

到目前为止,我已经实现了它首先说的逻辑,它将检查列表是否为空或列表中的任何一个元素 [True],将给出 1,[False] 将给出 0。

然后在这种情况下binToDecList (x:xs) = binToDecList' x 0 我做了什么来处理第一个元素,无论这是真还是假。

binToDecList :: [Bool] -> Int
binToDecList []      = error "Empty List"
binToDecList [True]  = 1
binToDecList [False] = 0
binToDecList (x:xs)  =  binToDecList' x 0 
binToDecList' x d | x == True = mul (add d 1)
                  | otherwise = mul (add d 0)

add :: Int -> Int -> Int
add x y = x + y

mul :: Int -> Int
mul x = x * 2

我想在下一次迭代中使用binToDecList' 的结果,在列表的下一个元素上递归调用自身。我如何存储结果,然后递归地将其应用于列表的下一个元素。任何形式的帮助将不胜感激。

【问题讨论】:

  • 尝试使用fold
  • 如果你直接用map fromEnum[Bool]值转换成[Int]值列表会简单一点:binToDecList = go . map fromEnum where go = ...
  • Prelude 中查找foldl 的文档,然后尝试填充go 辅助函数的缺失定义:binToDecList = foldl go 0 where go acc x = ...
  • 谢谢大家,我可以使用折叠功能来执行此操作,但我仍然想知道为什么它无法通过显式递归执行?其次,还有一个问题,就是要执行一次额外的迭代以将结果相乘。我怎么能在这里控制它。如果下一个元素是 [ ],我尝试过这种方式,那么它只会返回到目前为止累积的结果。但是好像没有按预期运行可能是调用函数的组成不对吧?
  • 请指导: foldl(\result x -> if x == True then (mul(add result 1) xs) else (mul(add result 1) xs)) 0 xs and mul :: Int -> [Bool]->Int mul x b = if tail(b) /= [] then x * 2 else x 。我知道这个逻辑在这里可能不太好,但我现在想这样做,除非我走错了方向。有什么帮助吗?

标签: function haskell binary data-conversion


【解决方案1】:

foldl 的类型*告诉我们它必须如何工作。

foldl :: (b -> a -> b) -> b -> [a] -> b

很明显[a],第三个参数是一些东西的列表,必须是Bool 的列表,才能交给霍纳的算法。这意味着类型变量a 必须是Bool

类型变量b 表示可能不同的类型。我们正在尝试将[Bool] 转换为Int,因此Intb 的正确猜测。

foldl 的工作原理是从左侧(,从它的头部开始)浏览一个列表,并以某种方式将目前的结果与列表中的下一个元素结合起来。第二个参数通常命名为z,表示“零”或折叠过程的种子值。当foldl 到达列表末尾时,返回累加值。

我们可以从语法上看到,第一个参数是某个函数,它对 b 类型的项目执行一些操作,然后键入 a 以产生 b。现在,一个忽略 a 项并无条件生成 b 的函数会适合但不会很有趣。

想想霍纳的算法是如何进行的。图表上路径拐角处的数字代表上一段的名义上的“迄今为止的结果”。我们知道bIntaBool,所以传递给foldl的函数必须将Bool转换为Int,并结合结果。

Horner 算法的第一步似乎是一个特殊情况,需要以不同的方式处理,但foldl 始终使用相同的函数。如果您想象以一种不可见的水平移动(,乘以 2)开始“启动泵”,我们可以使这些类型像拼图一样组合在一起。没关系,因为两倍的零仍然是零。

因此,就foldl而言,霍纳的算法是

horners :: [Bool] -> Int
horners = foldl f 0
  where f x b =
          let b' = fromEnum b
          in 2*x + b'

注意2*x + b' 结合了后续的水平和垂直移动。

这也暗示了如何在直接递归中表达它。

horners' :: [Bool] -> Int
horners' [] = 0
horners' l  = go 0 l
  where -- over then down
        go x [] = x
        go x (b:bs) =
          let b' = fromEnum b
          in go (2*x + b') bs

这里的内部go 循环正在执行左折叠并将每个下一个Booli 中的结果组合起来。


* 教学上的简化:实际类型将列表类型概括为Foldable

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 2021-07-29
    • 2021-02-26
    • 2016-05-03
    • 2021-08-10
    相关资源
    最近更新 更多