我制成类似于numpy的的array的功能。其转换列表以阵列,列表的列表到2D阵列,等等。

它的工作原理是这样的:

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是必要的是,类型ai不能从ListOfIndex i a -> (i, i)ListOfIndex i a -> [a]分别回收。一个解决方法是将两种方法结合成型acArgs的一种方法ListOfIndex i a -> ((i, i), a)。现在唯一的问题是在其防止从typechecker太一般化太多引起同样的问题之前(例如,我们不能简单地用(Int, i))它的类型的方式来使用它在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

其他提示

如果你想保持acBoundsacFlatten独立的,你可以添加的型级别的标签参数它,即acBounds将有类型acBounds :: Proxy a -> ListOfIndex i a -> (i, i)。这消除了对undefined参数的需要,因为你可以通过(Proxy :: SomeConcreteType)它;和acBounds没有提取任何有用值级别的信息的方式,因为它同构(在一个无类型的方式)的单元类型。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top