문제

나는 Numpy 's와 비슷한 기능을 만들었습니다 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에 대한 추가 주장이 필요한 이유는 a 그리고 i 회수 할 수 없습니다 ListOfIndex i a -> (i, i) 그리고 ListOfIndex i a -> [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

다른 팁

당신이 유지하고 싶다면 acBounds 그리고 acFlatten 별도로 추가 할 수 있습니다 유형 수준 태그 인수 그것에, 즉 acBounds 유형이있을 것입니다 acBounds :: Proxy a -> ListOfIndex i a -> (i, i). 이것은 필요를 제거합니다 undefined 당신은 단지 통과 할 수 있기 때문에 논쟁 (Proxy :: SomeConcreteType) 그것에; 그리고 acBounds 유용한 값 수준 정보를 추출 할 수있는 방법이 없습니다. 이는 단위 유형에 동형 (비 형성 된 방식)이기 때문입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top