Haskell Typ Familien und Dummy-Argumente
-
19-09-2019 - |
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))
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.