我正在尝试在haskell中编写hyperoperation函数。haskell - hyperoperation(ackermann)函数,tetration
它通常被认为是ackermann(a,b,n)
,但对于部分应用目的,我认为首先放n
更有意义。因此我称它hypOp n a b
我找到了最自然的褶皱使用AO replicate
列表这样的形式:
Prelude> replicate 3 5
[5,5,5]
Prelude> foldr1 (*) $ replicate 3 5
125
根据函数参数的褶皱这可能是另外,mutliplication,幂,迭代幂次等
非正式概述:
hypOp 0 a _ = succ a
hypOp 1 a b = a + b = foldr1 (succ a) (replicate b a) --OFF BY ONE ISSUES, TYPE ISSUES
hypOp 2 a b = a * b = foldr1 (+) $ replicate b a
hypOp 3 a b = a^b = foldr1 (*) $ replicate b a
hypOp 4 a b = = foldr1 (^)
对于联想的原因,我的IM下我必须使用正确的褶皱,这是不幸的,因为左褶皱(foldl'
)的严格性会很有用。
权与左折叠问题
Prelude> foldl1 (^) $ replicate 4 2 --((2^2)^2)^2 = (4^2)^2 = 16^2 = 256 != 2 tetra 4
256
Prelude> foldr1 (^) $ replicate 4 2 --(2^(2^(2^2))) = 2^16 = 65536 == 2 tetra 4
65536
我是说我“开始”与后继功能的一开始就偏离接一个的问题。所以不是即时通讯使用(+)作为我的基地功能折叠
Prelude> let add a b = foldr1 (\a b -> succ b) $ replicate b a
Prelude> add 5 4
8
Prelude> add 10 5 --always comes out short by one, so i cant build off this
14
开始几n
值,做“手动”:
Prelude> let mul a b = foldr1 (+) $ replicate b a
Prelude> let exp a b = foldr1 mul $ replicate b a
Prelude> let tetra a b = foldr1 exp $ replicate b a
Prelude> let pent a b = foldr1 tetra $ replicate b a
Prelude> let sixate a b = foldr1 pent $ replicate b a
Prelude> mul 2 3 --2+2+2
6
Prelude> exp 2 3 --2*2*2
8
Prelude> tetra 2 3 --2^(2^2)
16
Prelude> pent 2 3 --2 tetra (2 tetra 2)
65536
Prelude> sixate 2 3
*** Exception: stack overflow
我在直通上面的方法正式定义的尝试
hypOp :: Int -> Int -> Int -> Int
hypOp 0 a b = succ a
hypOp 1 a b = (+) a b --necessary only bc off-by-one error described above
hypOp n a b = foldr1 (hypOp $ n-1) (replicate b a)
其他企图双向递归数组(没有任何显着的差异):
let arr = array (0,5) ((0, (+)) : [(i, (\a b -> foldr1 (arr!(i-1)) (replicate b a))) | i <- [1..5]])
-- (arr!0) a b makes a + b
-- (arr!1) a b makes a * b, etc.
所以我的问题是...
- 任何一般性的建议,不同的appraoches到t他的功能?我似乎找不到一种方法来避免溢出,除非使用非常“势在必行”的风格,这在使用哈斯克尔并尝试以惯用风格编码时并不是我的意图。
- 我可以如何处理我的错误问题所以我可以在最底部开始'正确'
succ
- 严格性和左侧与右侧褶皱。有没有在
seq
中工作的方法?有些方法可以使用foldl1'
而不是foldr1
并避免上述问题?
好的谢谢你的提示。因为'纯粹'/教育编号喜欢试着只将'succ'作为一个基本案例来定义,并且从其中构建所有其他的东西,加法和向上。我会试着让这个论证翻转过来。如果我试图让一个高性能的版本号建立在指数的基础上。你有没有想到比皱褶更有效的方法? – 2011-05-11 16:36:41
@jon_darkstar:也许你可以做一些类似于倍增,一般情况下取平方的运算?我不太熟悉hyperoperations,所以我不确定。 – hammar 2011-05-11 16:44:05
顺便说一句 - 我喜欢你的答案,并提供了upvoted它,但我还没有接受bc即时通讯仍在玩这个和id喜欢留下的问题暂时打开 – 2011-05-22 07:33:59