Al entrar en Haskell, estoy tratando de reproducir algo como la remodelación de Numpy con listas. Específicamente, dada una lista plana, reconfórmela en una lista n-dimensional:
import numpy as np
a = np.arange(1, 18)
b = a.reshape([-1, 2, 3])
# b =
#
# array([[[ 1, 2, 3],
# [ 4, 5, 6]],
#
# [[ 7, 8, 9],
# [10, 11, 12]],
#
# [[13, 14, 15],
# [16, 17, 18]]])
Pude reproducir el comportamiento con índices fijos, por ejemplo:
*Main> reshape23 [1..18]
[[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]]
Mi código es:
takeWithRemainder :: (Integral n) => n -> [a] -> ([a], [a])
takeWithRemainder _ [] = ([], [])
takeWithRemainder 0 xs = ([], xs)
takeWithRemainder n (x:xs) = (x : taken, remaining)
where (taken, remaining) = takeWithRemainder (n-1) xs
chunks :: (Integral n) => n -> [a] -> [[a]]
chunks _ [] = []
chunks chunkSize xs = chunk : chunks chunkSize remainderOfList
where (chunk, remainderOfList) = takeWithRemainder chunkSize xs
reshape23 = chunks 2 . chunks 3
Ahora, parece que no puedo encontrar una manera de generalizar esto a una forma arbitraria. Mi idea original era hacer un pliegue:
reshape :: (Integral n) => [n] -> [a] -> [b]
reshape ns list = foldr (\n acc -> (chunks n) . acc) id ns list
Pero, no importa cómo lo haga, siempre obtengo un error de tipo del compilador. Según tengo entendido, el problema es que en algún momento, acc
se infiere que el tipo para es id
ie a -> a
, y no le gusta el hecho de que la lista de funciones en el pliegue tiene un tipo diferente (aunque compatible para la composición) firma. Me encuentro con el mismo problema tratando de implementar esto con recursividad yo mismo en lugar de un pliegue. Esto me confunde porque originalmente me había propuesto para el [b]
de reshape
's firma de tipo a ser un sustituto de 'otra, de tipo disociado' que podría ser cualquier cosa de [[a]]
a [[[[[a]]]]]
.
¿Cómo me estoy equivocando sobre esto? ¿Hay alguna manera de lograr realmente el comportamiento que pretendía, o es simplemente incorrecto querer este tipo de comportamiento "dinámico" en primer lugar?
(..)
parte estáimport Data.Proxy (Proxy(..))
?(..)
significa importar todos los constructores de tipos de datos y posiblemente los campos de registro. ComoProxy
solo tiene un constructor, es equivalente aProxy(Proxy))
La respuesta de @Fyodor Soikin es perfecta con respecto a la pregunta real. Excepto que hay un pequeño problema con la pregunta en sí. Las listas de listas no son lo mismo que una matriz. Es un error común pensar que Haskell no tiene matrices y que se ve obligado a lidiar con listas, que no podrían estar más lejos de la realidad.
Debido a que la pregunta está etiquetada
array
y hay una comparaciónnumpy
, me gustaría agregar una respuesta adecuada que maneje esta situación para las matrices multidimensionales. Hay un par de bibliotecas de matrices en el ecosistema de Haskell, una de las cuales esmassiv
Una
reshape
funcionalidad similarnumpy
se puede lograr mediante laresize'
función:fuente