Domanda

Ho fatto una funzione simile a array di NumPy. Converte le liste di array, liste di liste di array 2d, ecc.

Funziona in questo modo:

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 di una tupla. (Domanda lato:? C'è modo)

La codifica di esso era scomodo e ho dovuto fare un "workaround" (passando intorno argomenti fittizi per funzioni) per farlo funzionare. 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 è l'argomento undefined fittizio che passa sul posto di lavoro. Racconta la GHC quale istanza di ListOfIndex da utilizzare.

instance ArrConv () where
  acBounds _ = const ((), ())
  acFlatten _ = (: [])

La funzione di seguito 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 una funzione in una definizione di caso ..

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))
È stato utile?

Soluzione

Il motivo che gli argomenti extra per acBounds e acFlatten sono necessaria è che i tipi a e i non possono essere recuperati rispettivamente da ListOfIndex i a -> (i, i) e ListOfIndex i a -> [a]. Una soluzione è quella di combinare i due metodi in un metodo di tipo acArgs ListOfIndex i a -> ((i, i), a). Ora l'unico problema è utilizzare nel caso di (Int, i) in un modo che impedisce controllore dei tipi di generalizzare suo tipo troppo causando lo stesso problema di prima (per esempio, non possiamo utilizzare semplicemente fst . acArgs).

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

import Data.Array

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
  acArgs :: ListOfIndex i a -> ((i, i), [a])

instance ArrConv () where
  acArgs x = (((), ()), [x])

instance ArrConv i => ArrConv (Int, i) where
  acArgs lst =
    (((0, inStart), (length lst - 1, inEnd)), args >>= snd)
    where
      args = map acArgs lst
      (inStart, inEnd) = fst (head args)

arrFromNestedLists :: ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists = uncurry listArray . acArgs

Altri suggerimenti

Se si desidera mantenere acBounds e acFlatten separata, è possibile aggiungere una tipo a livello di tag nofollow argomento ad esso, vale a dire acBounds avrebbe tipo acBounds :: Proxy a -> ListOfIndex i a -> (i, i). Ciò elimina la necessità per gli argomenti undefined, dal momento che si può solo passare (Proxy :: SomeConcreteType) ad esso; e acBounds non ha modo di estrarre tutte le informazioni utili a livello di valore da esso, dal momento che è isomorfo (in modo non tipizzato) per il tipo di unità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top