Haskell 尝试添加两个数字时出现算术错误
我尝试实现一个函数,该函数接受一个限制和一个字符串,解析该字符串并测试解析的数字是否超过限制。该函数仅适用于不带0的字符串,如Haskell 尝试添加两个数字时出现算术错误,haskell,Haskell,我尝试实现一个函数,该函数接受一个限制和一个字符串,解析该字符串并测试解析的数字是否超过限制。该函数仅适用于不带0的字符串,如“123”。但是,它无法正确解析字符串,如“100”,其结果是1 是什么导致了这个问题 下面是代码 reachBounded :: Int -> String -> Maybe Int reachBounded limit str = case str of "" -> Nothing "0" -> Just 0 _
“123”
。但是,它无法正确解析字符串,如“100”
,其结果是1
是什么导致了这个问题
下面是代码
reachBounded :: Int -> String -> Maybe Int
reachBounded limit str = case str of
"" -> Nothing
"0" -> Just 0
_ -> foldr (\digit s -> do
sum <- s
let n = sum * 10 + digitToInt digit
guard (isDigit digit)
guard (n <= limit)
return n)
(Just 0) str
reachBounded::Int->String->Maybe Int
到达边界限制str=案例str
“->什么都没有
“0”->仅为0
_->foldr(\digits s->do
sum这是解决问题的一种非常必要的方法,如果你继续这样想,你将很难前进
以下是您可能希望重新思考问题的方式:
将“我有一个字符列表,但我想要数字,我将迭代并逐个替换”替换为“我有一个字符列表,但我想要数字,我将一次替换所有字符”(我假设您希望自己完全手动解析字符串,而不只是使用读取或某种解析工具)
到目前为止,我们已经:
reachBounded limit str = ... map digitToInt str
接下来,您要将这些数字转换为一个数字。将“我想通过此列表迭代增加一个和”替换为“我需要知道每个数字的位置值”。我们可以通过反转数字并将其与列表[1,101001000…]成对相乘来完成此操作。我们可以通过映射(10^)生成位置值列表在正整数列表上,或声明每个元素是前一个元素的10倍,从1开始。让我们使用后一个:
reachBounded limit str = ... zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
我们需要这些位置值的总和:
reachBounded limit str = ... where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
最后,我们必须检查它是否在给定的范围内:
reachBounded limit str = val <$ guard (val < limit) where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
或者使用Safe
库
bounded l = toMaybe (<l) <=< readMay
这更直接地封装了提前停止折叠并跟踪中间结果——即使您也可以提前停止折叠并跟踪中间结果——这是目前考虑的一种更简单的方式。这将为您提供所有中间状态的完整列表以及迭代器所需的结果或错误函数可以选择以终止
正在将解决方案转换为此格式
reachBounded limit str = iterateE iter (Just 0,str) where
iter (n, []) = Final n
iter (n, (s:str)) = Next (do
sum <- s
let n = sum * 10 + digitToInt digit
guard (isDigit digit)
guard (n <= limit)
return n, str)
reachBounded limit str=iterateE iter(仅0,str),其中
iter(n,[])=最终n
iter(n,(s:str))=Next(do
sum这是解决问题的一种非常必要的方法,如果你继续这样想,你将很难前进
以下是您可能希望重新思考问题的方式:
将“我有一个字符列表,但我想要数字,我将迭代并逐个替换”替换为“我有一个字符列表,但我想要数字,我将一次替换所有字符”(我假设您希望自己完全手动解析字符串,而不只是使用读取或某种解析工具)
到目前为止,我们已经:
reachBounded limit str = ... map digitToInt str
接下来,您要将这些数字转换为一个数字。将“我想通过此列表迭代增加一个和”替换为“我需要知道每个数字的位置值”。我们可以通过反转数字并将其与列表[1,101001000…]成对相乘来完成此操作。我们可以通过映射(10^)生成位置值列表在正整数列表上,或声明每个元素是前一个元素的10倍,从1开始。让我们使用后一个:
reachBounded limit str = ... zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
我们需要这些位置值的总和:
reachBounded limit str = ... where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
最后,我们必须检查它是否在给定的范围内:
reachBounded limit str = val <$ guard (val < limit) where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
或者使用Safe
库
bounded l = toMaybe (<l) <=< readMay
这更直接地封装了提前停止折叠并跟踪中间结果——即使您也可以提前停止折叠并跟踪中间结果——这是目前考虑的一种更简单的方式。这将为您提供所有中间状态的完整列表以及迭代器所需的结果或错误函数可以选择以终止
正在将解决方案转换为此格式
reachBounded limit str = iterateE iter (Just 0,str) where
iter (n, []) = Final n
iter (n, (s:str)) = Next (do
sum <- s
let n = sum * 10 + digitToInt digit
guard (isDigit digit)
guard (n <= limit)
return n, str)
reachBounded limit str=iterateE iter(仅0,str),其中
iter(n,[])=最终n
iter(n,(s:str))=Next(do
sum1+((10*0)+(10*0+0))
等于一。也许你想要foldl
?@ThomasM.DuBuisson是的!我多粗心啊。谢谢。1+((10*0)+(10*0+0))
等于一。也许你想要foldl
?@ThomasM.DuBuisson是的!我真粗心LOL。非常感谢。公平地说,使用read
会稍微改变语义。-18478429
和((42))
都是43或更多边界的有效字符串。我经常抛出确保px=x,因此每当我需要命令式调试器时,这表明我没有从功能上思考问题?这是一个非常好的迹象是的。很多功能上的思考都是以纯方式转换值,并将一系列转换组合到产生所需的结果。由于您可以简单地将所有相关内容的整个中间状态视为一个正常值,并且您的转换是以相等的方式定义的,因此,当您真正以纯函数的方式进行思考时,传统调试器的作用往往会小得多。当然,有时您无法做到这一点以纯粹的功能性方式做某事,但这种方式并不常见。公平地说,使用read
会稍微改变语义。-18478429
和((42))
都是43或更多边界的有效字符串。我经常抛出确保px=x,因此每当我需要命令式调试器时,这表明我没有从功能上思考问题?这是一个非常好的迹象是的。很多功能上的思考都是以纯方式转换值,并将一系列转换组合到产生所需的结果。因为你可以简单地把所有相关的中间状态看作一个正常值,你的转换被定义为equati