Zrobiłem funkcję podobną do numpy's array
. Konwertuje list do tablic, list list do 2D tablice itpRodziny typu Haskella i atrapy argumentów
To działa tak:
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,()))
a nie (Int, Int)
bo nie wiem o Zautomatyzowane sposób, aby zwiększyć długość krotka. (pytanie boczne: czy jest taki sposób?)
Kodowanie było niewygodne i musiałem zrobić "obejście" (przekazywanie fałszywych argumentów do funkcji), aby działało. Zastanawiam się, czy jest lepszy sposób.
Więc oto kod, przerwane ze szczegółami brzydkie obejścia:
{-# 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
"powinno" być :: ListOfIndex i a -> (i, i)
. I podobnie dla acFlatten
. Każdy podany jest obojętne zmienną (undefined
jest zawsze podana wartość), ponieważ w przeciwnym razie nie mogę zmusić go do kompilacji :(
arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
listArray
(acBounds (undefined :: a) lst)
(acFlatten (undefined :: i) lst)
Powyżej jest obojętne undefined
argumentem przechodząc w pracy. To opowiada GHC która instancję ListOfIndex
użyć.
instance ArrConv() where
acBounds _ = const ((),())
acFlatten _ = (: [])
Poniższa funkcja powinna być funkcja w instancji ArrConv
acBounds
i jest zadeklarowana poza tylko dlatego, że muszę korzystać ScopedTypeVariables
i nie wiem, jak mogę to zrobić w funkcja w definicji instancji.
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))
"Nie znam programistycznego sposobu zwiększenia długości krotki." Nie sądzę, że możesz. To doskonały przykład funkcji, której typ zależy od wartości. Byłoby to łatwe do zrobienia w niezmiennie wpisywanym języku, jak "Agda", ale niemożliwe w Haskell. Może mógłbyś użyć "GADTs" w jakiś sposób, by dać ci jakieś uzależniające zachowanie, ale poza tym nie wiem jak. –
Może Szablon Haskell może być przydatny: http://www.haskell.org/bz/thdoc.htm http://www.haskell.org/haskellwiki/Template_Haskell – primodemus
@primodemus: Z TH mógłbym zrobić przykłady dla 'ArrConv' w przypadku tablic o maksymalnie 10 wymiarach i będą używać normalnych krotek dla indeksów, co jest poprawą.Ale czułbym, że limit jest arbitralny, a kod prawdopodobnie będzie znacznie mniej czytelny. – yairchu