سؤال

لقد قمت بإنشاء وظيفة مشابهة لـ numpy's array.يقوم بتحويل القوائم إلى صفائف، وقوائم القوائم إلى صفائف ثنائية الأبعاد، وما إلى ذلك.

يعمل مثل هذا:

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).

} : ListOfIndex IA -> ((I، I)، [A]) مثيل arrcrconv () حيث أكارات X = (((()، ())، [x]) مثيل arrcrconv i => arrcrconv (int، i) حيث أكارات LST = (((0، Instart)، (طول LST - 1، Inend))، Args >> = SND) حيث Args = Map Acargs Lst (Instart، Innend) = FST (Head Args) Arrfromnestedlists :: Arrconv I => ListOfIndex IA -> صفيف IA ArrFromnestfedlists = Listray Uncurry Listray. أكارات

نصائح أخرى

إذا كنت تريد الاحتفاظ بها acBounds و acFlatten منفصلة، ​​يمكنك إضافة وسيطة العلامة على مستوى النوع إليه، أي. acBounds سيكون له نوع acBounds :: Proxy a -> ListOfIndex i a -> (i, i).وهذا يلغي الحاجة إلى undefined الحجج، حيث يمكنك تمرير فقط (Proxy :: SomeConcreteType) إليها؛و acBounds ليس لديه طريقة لاستخراج أي معلومات مفيدة على مستوى القيمة منه، لأنه متماثل (بطريقة غير مكتوبة) لنوع الوحدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top