2011-12-21 9 views
8

Haskell ha la funzione di sommaCubesumming in haskell

sum :: Num a => [a] -> a 

Quale può essere ben composto sommare una matrice da

sum . map sum :: Num a => [[a]] -> a 

Andando più profondo, tuttavia, come somma di un cubo, crea la restrizione Num [a]

sum . map sum . map sum :: (Num a, Num [a]) => [[[a]]] -> a 

Il che, se ci pensate, è naturale. Quindi, con il precedente tentativo di definire la funzione sumcube che esplode in faccia, dobbiamo trovare un percorso diverso. Uno di questi tentativi potrebbe essere:

sum . map sum . map (map sum) :: Num a => [[[a]]] -> a 

Che non sembra naturale come la funzione di sommatore.

Nella mia ricerca per posessing degli strumenti mentali per la risoluzione dei problemi in Haskell, sono interessato a sapere come affrontare questo problema di sommare una struttura di qualsiasi profondità, ad esempio, impilando map sum s come nel mio terzo esempio di codice. È possibile? E in tal caso, come lo faresti?

+0

Hai provato 'somma. mappa (mappa somma) '? – fuz

+0

somma. map (map sum) :: (Num [b], Num b) => [[[b]]] -> [b] –

+0

Se sei interessato a operazioni veloci su matrici numeriche, dovresti probabilmente usare vector, repa, hmatrix o pacchetti simili. –

risposta

12

Dovrai lavorare da dentro. Quando si ha una funzione f per sommare una struttura dati, quindi sum . map f è il modo di sommare un elenco di tali strutture dati.

     sum :: Num a => [a] -> a 
      sum . map sum :: Num a => [[a]] -> a 
sum . map (sum . map sum) :: Num a => [[[a]]] -> a 
+0

è un bel modo di vederlo –

+0

Scelgo questa come risposta accettata perché spiega il problema nel modo migliore. –

0

In primo luogo, c'è Template Haskell (estensione GHC). Oppure si potrebbe usare un data che supporta arbitrario lista profonda nidificazione così:

data Tree a = Leaf a | Node [Tree a] 

sumTree (Leaf x) = x 
sumTree (Node xs) = (sum . map sumTree) xs 

main = print $ sumTree $ Node [ Node [Leaf 3, Leaf 4, Leaf 5] 
           , Node [Leaf 1, Leaf 4, Leaf 2]] 

che stamperà 19 qui. Tuttavia questo non garantisce che tutte le foglie abbiano la stessa profondità di annidamento e non so come costruirla dagli elenchi.

5

Forse questo? Assume l'associatività, ma l'aggiunta di un nuovo livello è semplice

sum . concat . concat :: Num c => [[[c]]] -> c 
+0

Concat era in realtà la mia motivazione per la domanda.Concat compone meravigliosamente quale somma non lo è, immagino perché la somma ha una restrizione di tipo. Punto preso. –

+2

'concat' rimuove i layer dall'esterno del tipo, mentre' sum' deve rimuovere i layer dall'interno. Contrasto 'concat. concat' e 'somma. mappa sum' con 'concat. mappa concat'. – dave4420

+1

@MagnusKronqvist: La differenza è che 'concat' opera interamente sugli elenchi, mentre' sum' opera sugli elementi. Con quest'ultimo è sempre necessario iniziare con la lista più interna, ma qualsiasi "lista di liste" può essere concatenata. Questo è il concetto fondamentale dietro le liste essendo una monade, per inciso. –

14

E le tipette?

class Summable a where 
    total :: a -> Int 

instance Summable Int where 
    total = id 

instance Summable x => Summable [x] where 
    total = sum . map total 

total ([[[1,2,3],[4,5]],[[6],[7,8,9,10]]] :: [[[Int]]]) 
--55 
+0

Dannato, mi hai battuto! –

+0

Aspetto interessante in effetti. Scala piacevolmente il numero –

+1

- purtroppo non posso accettare risposte - questo è un concetto che voglio tenere a mente. – epsilonhalbe

1

Sembra più naturale per me per definire di sum in termini di dimensioni del precedente sum una dimensione ulteriore.

-- given sum :: Num a => [a] -> a 

sum2 :: [[a]] -> a 
sum2 = sum . map sum 

sum3 :: [[[a]]] -> a 
sum3 = sum . map sum2 

sum4 :: [[[[a]]]] -> a 
sum4 = sum . map sum3 

Questa è fondamentalmente la stessa idea di quello che ha detto Sjoerd. Se si desidera utilizzare solo map e sum e non refactoring sottoespressioni comuni in nomi utili ... quindi utilizzare il ragionamento equazionale per sostituire le funzioni personalizzate sum2, sum3, ecc