Estoy tratando de escribir una función de hiperoperación en haskell.haskell - función de hiperoperación (ackermann), tetration
Por lo general se escribe como ackermann(a,b,n)
, pero para fines de aplicación parcial, creo que tiene más sentido poner n
primero. Como tal, estoy llamando hypOp n a b
La forma usos más naturales que se encuentran He pliegues ao replicate
listas de la siguiente manera:
Prelude> replicate 3 5
[5,5,5]
Prelude> foldr1 (*) $ replicate 3 5
125
Dependiendo del argumento de la función al redil esto puede ser, además, mutliplication, exponenciación, tetración, etc.
general informal:
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 (^)
Por razones asociativos tengo la im Pression Debo usar pliegues derechos, lo cual es desafortunado porque la rigurosidad disponible con pliegues izquierdos (foldl'
) sería útil.
derecha vs. izquierda pliega tema
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
consigo un problema off-by-one cuando i 'Inicio' un principio con la función sucesor. así que en vez im usando (+) como la función de mi base de pliegue
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
primeros pocos n
valores, hecho 'manualmente':
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
Mi intento de definiciones formales thru enfoque anterior:
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)
Otro intento de matriz recursiva (no diferente de manera significativa):
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.
Así que mis preguntas son ...
- Cualquier sugerencia generales, diferentes appraoches a L a función? No puedo encontrar una manera de evitar desbordamientos a excepción de utilizar un estilo muy 'imperativo' que no es mi intención cuando uso Haskell y trato de codificar en un estilo idiomático
- Cómo se puede tratar mi problema de uno a uno así que puedo comenzar "correctamente" en la parte inferior con
succ
- Estricto y pliegues izquierdos y derechos. ¿Hay alguna manera de trabajar en
seq
? ¿De alguna forma puedo usarfoldl1'
en lugar defoldr1
y evitar el problema descrito anteriormente?
ok gracias por la punta. para la id de "pureza"/educación, como intentar definir solo "succ" como caso base, y construir todo lo demás, suma y ascendente, a partir de él. Voy a tratar de hacer que el argumento funcione con eso. si tuviera que intentar hacer una versión de id. de versión de rendimiento fuera de exponenciación. ¿Hay algún enfoque que tenga en mente que sea más eficiente que los pliegues? –
@jon_darkstar: Tal vez se puede hacer algo similar a la multiplicación por duplicación, exponenciación por cuadratura para el caso general? No estoy muy familiarizado con las hiperveloces así que no estoy seguro. – hammar
por cierto - me gusta su respuesta y ive upvoted, pero yo no he aceptado im bc sigue jugando con esto y como seria dejar la pregunta abierta por el momento –