Я сделал функцию подобной numpy's array
. Это преобразовывает списки в массивы, списки списков к 2-м массивам, и т.д.
Это работает как это:
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, ()))
и нет (Int, Int)
потому что я не знаю о программном способе увеличить длину кортежа. (вопрос о стороне: есть ли такой путь?)
Кодирование его было неловким, и я должен был сделать "обходное решение" (раздающий фиктивные аргументы функциям) для него для работы. Интересно, существует ли лучший путь.
Таким образом, вот код, прерванный деталями ужасных обходных решений:
{-# 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
"должен" быть :: ListOfIndex i a -> (i, i)
. И так же для acFlatten
. Каждому дают фиктивную переменную (undefined
всегда данное значение), потому что иначе я не мог заставить его компилировать :(
arrFromNestedLists :: forall i a. ArrConv i => ListOfIndex i a -> Array i a
arrFromNestedLists lst =
listArray
(acBounds (undefined :: a) lst)
(acFlatten (undefined :: i) lst)
Выше макет undefined
передача параметров на работе. Это говорит GHC который экземпляр ListOfIndex
использовать.
instance ArrConv () where
acBounds _ = const ((), ())
acFlatten _ = (: [])
Ниже функции должен был быть acBounds
функция в экземпляре ArrConv
, и объявляется снаружи только потому, что я должен использовать ScopedTypeVariables
и я не знаю, как я могу сделать это в функции в определении экземпляра..
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))
Причина, по которой необходимы дополнительные аргументы ACBounds и AcFlatten, заключается в том, что типы A
и I
не может быть восстановлено из listOfindex Ia -> (i, i)
и listofindex Ia -> [A]
соответственно. Один обходной путь состоит в том, чтобы объединить два метода в один метод ACARGS
типа ListOfindex I A -> ((i, i), a)
. Теперь единственная проблема состоит в том, чтобы использовать его в экземпляре (INT, I)
таким образом, что предотвращает обработку TypeChecker от обобщения своего типа, вызывающего одинаковую проблему, что и раньше (например, мы не можем просто использовать 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