J'ai créé une fonction similaire à celle de numpy array
. Il convertit les listes de tableaux, listes de listes à des tableaux 2d, etc.Familles de type Haskell et arguments fictifs
Il fonctionne comme ceci:
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,()))
et non (Int, Int)
parce que je ne sais pas d'une façon programatic d'augmenter la longueur un tuple. (question subsidiaire: y at-il une telle manière?)
Le codage de celui-ci était maladroit et j'ai dû faire une "solution de contournement" (en passant autour des arguments factices aux fonctions) pour que cela fonctionne. Je me demande s'il y a un meilleur moyen.
Alors, voici le code, interrompu par les détails des solutions de contournement laid:
{-# 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
"devrait" être :: ListOfIndex i a -> (i, i)
. Et de même pour acFlatten
. Chacun reçoit une variable factice (undefined
est toujours la valeur donnée), car sinon je ne pouvais pas le compiler :(
arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
listArray
(acBounds (undefined :: a) lst)
(acFlatten (undefined :: i) lst)
Au-dessus est l'argument undefined
fictif qui passe au travail. Il raconte l'GHC quelle instance de ListOfIndex
à utiliser.
instance ArrConv() where
acBounds _ = const ((),())
acFlatten _ = (: [])
la fonction ci-dessous aurait dû être la fonction acBounds
dans une instance de ArrConv
, et est déclarée en dehors seulement parce que je dois utiliser ScopedTypeVariables
et je ne sais pas comment je peux le faire dans un fonctionner dans une définition d'instance.
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))
"Je ne connais pas de méthode par programme pour augmenter la longueur d'un tuple." Je ne pense pas que tu puisses. C'est un exemple parfait d'une fonction dont le type dépend d'une valeur. Il serait facile de le faire dans une langue typée dépendante comme 'Agda', mais impossible dans Haskell. Peut-être pourriez-vous utiliser 'GADTs 'd'une façon ou d'une autre pour vous donner un comportement dépendant, mais je ne sais pas comment vous le faites. –
Peut-être que le modèle Haskell peut être utile: http://www.haskell.org/bz/thdoc.htm http://www.haskell.org/haskellwiki/Template_Haskell – primodemus
@primodemus: Avec TH, je pourrais créer des instances pour 'ArrConv' pour les tableaux de 10 dimensions maximum, et ils utiliseraient des tuples normaux pour les index, ce qui est une amélioration.Mais je pense que la limite est arbitraire et que le code va probablement être beaucoup moins lisible. – yairchu