Ho eseguito una funzione simile a numpy array
. Converte le liste per gli array, liste di liste per le matrici 2D, eccFamiglia di tipi Haskell e argomenti fittizi
funziona così:
ghci> arrFromNestedLists ["hello", "world"] :: Array (Int, (Int,())) Char
array ((0,(0,())),(1,(4,()))) [((0,(0,())),'h'),((0,(1,())),'e'),((0,(2,())),'l'),((0,(3,())),'l'),((0,(4,())),'o'),((1,(0,())),'w'),((1,(1,())),'o'),((1,(2,())),'r'),((1,(3,())),'l'),((1,(4,())),'d')]
(Int, (Int,()))
e non (Int, Int)
perché io non conosco un modo programmatico per aumentare la lunghezza del una tupla. (domanda a parte: c'è un modo?)
La codifica di esso era scomoda e dovevo fare una "soluzione" (passando gli argomenti fittizi alle funzioni) perché funzionasse. Mi chiedo se c'è un modo migliore.
Quindi, ecco il codice, interrotta con i dettagli del brutto soluzioni alternative:
{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, TypeFamilies #-}
type family ListOfIndex i a
type instance ListOfIndex() a = a
type instance ListOfIndex (Int, i) a = [ListOfIndex i a]
class Ix i => ArrConv i where
acBounds :: a -> ListOfIndex i a -> (i, i)
acFlatten :: i -> ListOfIndex i a -> [a]
acBounds
"dovrebbe" essere :: ListOfIndex i a -> (i, i)
. E allo stesso modo per acFlatten
. Ciascuno è data una variabile dummy (undefined
è sempre il valore dato) perché altrimenti non potrei farlo per compilare :(
arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
listArray
(acBounds (undefined :: a) lst)
(acFlatten (undefined :: i) lst)
Sopra è il manichino undefined
argomento passando al lavoro. Racconta la GHC quale istanza di ListOfIndex
da usare.
instance ArrConv() where
acBounds _ = const ((),())
acFlatten _ = (: [])
la funzione qui sotto avrebbe dovuto essere la funzione acBounds
in un'istanza di ArrConv
, ed è dichiarata fuori solo perché ho bisogno di usare ScopedTypeVariables
e non so come posso farlo in un funzione in una definizione di istanza
acSucBounds
:: forall a i. ArrConv i
=> a -> [ListOfIndex i a] -> ((Int, i), (Int, i))
acSucBounds _ lst =
((0, inStart), (length lst - 1, inEnd))
where
(inStart, inEnd) = acBounds (undefined :: a) (head lst)
instance ArrConv i => ArrConv (Int, i) where
acBounds = acSucBounds
acFlatten _ = concatMap (acFlatten (undefined :: i))
"Non conosco un modo programmatico per aumentare la lunghezza di una tupla." Non penso che tu possa Questo è un perfetto esempio di una funzione il cui tipo dipende da un valore. Sarebbe facile farlo in un linguaggio tipizzato come "Agda", ma impossibile in Haskell. Forse potresti usare 'GADTs 'in qualche modo per darti un comportamento dipendente, ma in cima alla mia testa, non so come. –
Forse Template Haskell può essere utile: http://www.haskell.org/bz/thdoc.htm http://www.haskell.org/haskellwiki/Template_Haskell – primodemus
@primodemus: Con TH ho potuto creare istanze per 'ArrConv' per matrici di fino a 10 dimensioni, e userebbero tuple normali per gli indici, che è un miglioramento.Ma mi sento come se il limite fosse arbitrario e il codice sarebbe probabilmente molto meno leggibile. – yairchu