Entrando em Haskell, estou tentando reproduzir algo como a remodelação de numpy com listas. Especificamente, dada uma lista simples, reformule-a em uma 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]]])
Consegui reproduzir o comportamento com índices fixos, por exemplo:
*Main> reshape23 [1..18]
[[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],[[13,14,15],[16,17,18]]]
Meu código é:
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
Agora, parece que não consigo encontrar uma maneira de generalizar isso para uma forma arbitrária. Minha ideia original era fazer uma dobra:
reshape :: (Integral n) => [n] -> [a] -> [b]
reshape ns list = foldr (\n acc -> (chunks n) . acc) id ns list
Mas, não importa como eu faça isso, sempre recebo um erro de tipo do compilador. Pelo que entendi, o problema é que, em algum momento, o tipo for acc
é inferido como id
ie a -> a
, e não gosta do fato de que a lista de funções na dobra tem um tipo diferente (embora compatível com a composição) assinatura. Eu me deparo com o mesmo problema tentando implementar isso com recursão em vez de uma dobra. Isso me confundiu porque originalmente eu tinha pretendido para o [b]
em reshape
's assinatura de tipo para ser um stand-in para 'um outro, tipo dissociada', que poderia ser qualquer coisa, desde [[a]]
a [[[[[a]]]]]
.
Como estou indo errado sobre isso? Existe uma maneira de realmente alcançar o comportamento que eu pretendia, ou é simplesmente errado querer esse tipo de comportamento "dinâmico" em primeiro lugar?
(..)
parteimport Data.Proxy (Proxy(..))
?(..)
significa importar todos os construtores de tipos de dados e possivelmente os campos de registro. ComoProxy
tem apenas um construtor, é equivalente aProxy(Proxy))
A resposta de @Fyodor Soikin é perfeita com relação à pergunta real. Exceto que há um pouco de problema com a própria pergunta. Listas de listas não é a mesma coisa que uma matriz. É um equívoco comum que Haskell não tenha matrizes e você seja forçado a lidar com listas, o que não poderia estar mais longe da verdade.
Como a pergunta está marcada
array
e existe uma comparação comnumpy
, eu gostaria de adicionar uma resposta adequada que lide com essa situação para matrizes multidimensionais. Existem algumas bibliotecas de matriz no ecossistema Haskell, uma das quais émassiv
Uma
reshape
funcionalidade semelhantenumpy
pode ser alcançada porresize'
função:fonte