Frage

habe ich eine ähnliche Funktion wie numpy des array. Er wandelt Listen Arrays, Listen von Listen zu 2D-Arrays, etc.

Es funktioniert wie folgt:

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, ())) und nicht (Int, Int), weil ich nicht weiß, von einem programmatischen Weg, um die Länge eines Tupels zu erhöhen. (Seite Frage: gibt es eine solche Art und Weise)

Die Codierung es war umständlich und ich hatte eine „Abhilfe“ (vorbei um Dummy-Argumente an Funktionen) für seine Arbeit zu tun. Ich frage mich, ob es ein besserer Weg.

So, hier ist der Code, mit Details der hässlichen Abhilfen unterbrochen:

{-# 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 "sollte" :: ListOfIndex i a -> (i, i) sein. Und in ähnlicher Weise für acFlatten. Jedes Zimmer ist ein Dummy-Variable gegeben (undefined ist immer der Wert angegeben), weil sonst hätte ich es nicht zu kompilieren: (

arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
  listArray
  (acBounds (undefined :: a) lst)
  (acFlatten (undefined :: i) lst)

Oben ist das Dummy undefined Argument bei der Arbeit vorbei. Es erzählt die GHC, welche Instanz von ListOfIndex zu verwenden.

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

Die unten Funktion sollte die acBounds Funktion in einer Instanz von ArrConv gewesen, und ist nur von außen erklärt, weil ich Gebrauch ScopedTypeVariables brauche, und ich weiß nicht, wie ich es in einer Funktion in einer Instanz Definition tun kann ..

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))
War es hilfreich?

Lösung

Der Grund, dass die zusätzlichen Argumente acBounds und acFlatten notwendig sind, ist, dass die Typen a und i nicht jeweils von ListOfIndex i a -> (i, i) und ListOfIndex i a -> [a] gewonnen werden. Eine Abhilfe besteht darin, die beiden Verfahren zu einem Verfahren vom Typ acArgs ListOfIndex i a -> ((i, i), a) zu kombinieren. Jetzt ist das einzige Problem ist es im Fall von (Int, i) in einer Art und Weise zu verwenden, die die typechecker auch von Generalisierung seiner Art verhindert viel verursacht das gleiche Problem wie vor (zum Beispiel können wir nicht einfach verwenden 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

Andere Tipps

Wenn Sie acBounds und acFlatten getrennt halten möchten, können Sie eine type-Level-Tag Argument es, das heißt acBounds würde Typ acBounds :: Proxy a -> ListOfIndex i a -> (i, i) haben. Dadurch entfällt die Notwendigkeit für die undefined Argumente, da man nur (Proxy :: SomeConcreteType) es passieren kann; und acBounds hat keine Möglichkeit, irgendeine nützliche Wert Ebene Informationen von ihm des Extrahieren, da es isomorph ist (in einer nicht typisierten Weise) an den Einheitstyp.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top