不使用+;Haskell中的操作员
我想将两个正数相加,而不使用任何基本运算符,如+进行加法。我已经解决了这个问题(在add“”函数中)(我认为)可能效率不高,但这不是现在的重点。我得到了很多类型错误,但我不知道如何处理,这对我来说是非常混乱的,因为它在纸上工作,我来自python 加上12457489不使用+;Haskell中的操作员,haskell,addition,Haskell,Addition,我想将两个正数相加,而不使用任何基本运算符,如+进行加法。我已经解决了这个问题(在add“”函数中)(我认为)可能效率不高,但这不是现在的重点。我得到了很多类型错误,但我不知道如何处理,这对我来说是非常混乱的,因为它在纸上工作,我来自python 加上12457489 --add :: Int -> Int -> Int add x y = add'' (zip (add' x) (add' y)) where add' :: Int -> [Int] add' 0 =
--add :: Int -> Int -> Int
add x y = add'' (zip (add' x) (add' y))
where
add' :: Int -> [Int]
add' 0 = []
add' x = add' (x `div` 10) ++ [x `mod` 10]
转换[1,2,4,5][7,4,8,9],然后将它们压缩在一起[(1,7),(2,4)…]
总结[8,6,…]当总和达到10时发生的情况尚未实施
where
--add''' :: (Int,Int) -> Int
add''' x y = last (take (succ y) $ iterate succ x)
将两个数字相加
head
和last
。。。坦率地说,您根本不应该使用这些函数,因为它们是不安全的(部分),但它们可以在列表中使用。在Haskell中,列表与元组完全不同。要获取元组的元素,请使用模式匹配 (要获得列表中的元素,模式匹配通常也是最好的。)或者,您可以使用
fst
和snd
,这两种方法在2元组上执行您显然认为head
和last
的操作添加''
的方式,它的类型签名实际上是Int->Int->Int
。这相当于(Int,Int)->Int
,但它仍然与类型检查器不同add'
的结果是[Int]
,但您试图在add
的结果中将其用作Int
。那不行,你需要再次把数字转换成数字添加“”
不处理空案例。这很容易修复,但比递归更好的是使用标准的组合符。在您的情况下,这只应在元素方面工作,因此您可以简单地使用map
——或者在压缩中使用zipWith
。然后,您也不需要打开任何元组,因为它与curried函数一起工作您尝试的干净版本:
add :: Int -> Int -> Int
add x y = fromDigits 0 $ zipWith addDigits (toDigits x []) (toDigits y [])
where
fromDigits :: Int -> [Int] -> Int
fromDigits acc [] = acc
fromDigits acc (d:ds)
= acc `seq` -- strict accumulator, to avoid thunking.
fromDigits (acc*10 + d) ds
toDigits :: Int -> [Int] -> [Int] -- yield difference-list,
toDigits 0 = id -- because we're consing
toDigits x = toDigits (x`div`10) . ((x`mod`10):) -- left-associatively.
addDigits :: Int -> Int -> Int
addDigits x y = last $ take (succ x) $ iterate succ y
请注意,zipWith
要求两个数字的位数相同(正如zip
)
另外,是的,我在fromDigits
中使用了+
,这使得整个事情变得毫无意义。实际上,你当然会使用二进制,然后它只是一个按位or,乘法是一个左移位。实际上,您不需要在这里特别注意10溢出,但这只是因为在fromdights
中使用+
的欺骗
head
和last
。。。坦率地说,您根本不应该使用这些函数,因为它们是不安全的(部分),但它们可以在列表中使用。在Haskell中,列表与元组完全不同。要获取元组的元素,请使用模式匹配 (要获得列表中的元素,模式匹配通常也是最好的。)或者,您可以使用
fst
和snd
,这两种方法在2元组上执行您显然认为head
和last
的操作添加''
的方式,它的类型签名实际上是Int->Int->Int
。这相当于(Int,Int)->Int
,但它仍然与类型检查器不同add'
的结果是[Int]
,但您试图在add
的结果中将其用作Int
。那不行,你需要再次把数字转换成数字添加“”
不处理空案例。这很容易修复,但比递归更好的是使用标准的组合符。在您的情况下,这只应在元素方面工作,因此您可以简单地使用map
——或者在压缩中使用zipWith
。然后,您也不需要打开任何元组,因为它与curried函数一起工作您尝试的干净版本:
add :: Int -> Int -> Int
add x y = fromDigits 0 $ zipWith addDigits (toDigits x []) (toDigits y [])
where
fromDigits :: Int -> [Int] -> Int
fromDigits acc [] = acc
fromDigits acc (d:ds)
= acc `seq` -- strict accumulator, to avoid thunking.
fromDigits (acc*10 + d) ds
toDigits :: Int -> [Int] -> [Int] -- yield difference-list,
toDigits 0 = id -- because we're consing
toDigits x = toDigits (x`div`10) . ((x`mod`10):) -- left-associatively.
addDigits :: Int -> Int -> Int
addDigits x y = last $ take (succ x) $ iterate succ y
请注意,zipWith
要求两个数字的位数相同(正如zip
)
另外,是的,我在
fromDigits
中使用了+
,这使得整个事情变得毫无意义。实际上,你当然会使用二进制,然后它只是一个按位or,乘法是一个左移位。实际上,您不需要在这里特别注意10溢出,但这只是因为在fromDigits
中使用+
的欺骗,head
和last
您的意思是fst
和snd
,但您根本不需要它们,组件就在那里:
add'' :: [(Int, Int)] -> [Int]
add'' (pair : pairs) = [(add''' pair)] ++ add'' pairs
where
add''' :: (Int, Int) -> Int
add''' (x, y) = last (take (succ y) $ iterate succ x)
= iterate succ x !! y
= [x ..] !! y -- nice idea for an exercise!
现在仍然存在的一个大问题是如何处理这些可怕的10以上数字。这里有一个想法:生成一个数字和一个进位
= ([(d, 0) | d <- [x .. 9]] ++ [(d, 1) | d <- [0 ..]]) !! y
=([(d,0)| dByhead
和last
您的意思是fst
和snd
,但您根本不需要它们,组件就在那里:
add'' :: [(Int, Int)] -> [Int]
add'' (pair : pairs) = [(add''' pair)] ++ add'' pairs
where
add''' :: (Int, Int) -> Int
add''' (x, y) = last (take (succ y) $ iterate succ x)
= iterate succ x !! y
= [x ..] !! y -- nice idea for an exercise!
现在剩下的一个大问题是如何处理那些可怕的10以上的大数字。这里有一个想法:生成一个数字和一个带进位的数字
= ([(d, 0) | d <- [x .. 9]] ++ [(d, 1) | d <- [0 ..]]) !! y
=([(d,0)| d其他答案涵盖了您的方法中出现的错误。但是,从理论角度来看,它们都有一些缺点:它们要么将您置于[Int]
而不是Int
,要么在从[Int]返回的转换过程中使用(+)
到Int
。此外,它们使用mod
和div
作为定义加法的子例程——这是可以的,但从理论上讲,您需要确保
add 0 y = y
add x y
| x>0 = add (pred x) (succ y)
| otherwise = add (succ x) (pred y)