我做了一个类似于numpy的array
的函数。它可以转换列表以阵列,列表,以二维数组列表等Haskell类型族和虚拟参数
它的工作原理是这样的:
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 _ = (: [])
下面的功能应该已经在ArrConv
一个实例acBounds
功能,并且对外宣称只是因为我需要使用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))
“我不知道增加元组长度的编程方式。”我不认为你可以。这是一个功能的完美例子,其类型取决于一个值。使用像'Agda'这样的依赖类型语言很容易,但在Haskell中是不可能的。也许你可以以某种方式使用'GADTs'来给你一些依赖性的行为,但是我不知道如何。 – 2010-01-11 21:02:44
也许模板Haskell可能很有用:http://www.haskell.org/bz/thdoc.htm http://www.haskell.org/haskellwiki/Template_Haskell – primodemus 2010-01-12 00:19:28
@primodemus:有了TH,我可以为'ArrConv'对于多达10个维度的数组,它们将使用正常的元组作为索引,这是一种改进。但是我觉得这个限制是任意的,代码的可读性可能会低得多。 – yairchu 2010-01-12 07:33:31