تحويل نوع مثيلات الأسرة إلى كثافة العمليات

StackOverflow https://stackoverflow.com//questions/9705112

  •  14-12-2019
  •  | 
  •  

سؤال

لدي هذا الرمز:

type family Id obj :: *
type instance Id Box = Int

وأريد أن تجعل من ذلك يمكنني دائما الحصول على كثافة العمليات من عائلة نوع الهوية.أدرك أن التحويل سيكون مطلوبا.

اعتقدت ربما خلق فئة من شأنه أن يعمل:

class IdToInt a where
  idToInt :: Id a -> Int

instance IdToInt Box where
  idToInt s = s

وهذا يجمع في الواقع.ولكن عندما أحاول استخدامه:

testFunc :: Id a -> Int
testFunc x = idToInt x

أحصل على خطأ:

src/Snowfall/Spatial.hs:29:22:
Couldn't match type `Id a0' with `Id a'
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x

وبالتالي, كيف يمكنني إنشاء تحويل لمعرف نوع الأسرة للحصول على كثافة العمليات?

استنادا إلى الجواب من قبل إهيرد ، حاولت ما يلي لكنه لا يعمل إما:

class IdStuff a where
  type Id a :: *
  idToInt :: Id a -> Int

instance IdStuff Box where
  type Id Box = Int
  idToInt s = s

testFunc :: (IdStuff a) => Id a -> Int
testFunc x = idToInt x

يعطي خطأ:

src/Snowfall/Spatial.hs:45:22:
Could not deduce (Id a0 ~ Id a)
from the context (IdStuff a)
  bound by the type signature for
             testFunc :: IdStuff a => Id a -> Int
  at src/Snowfall/Spatial.hs:45:1-22
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
هل كانت مفيدة؟

المحلول

كما أشار آخرون ، والمشكلة هي أن المترجم لا يمكن معرفة أي a لاستخدام.تعد عائلات البيانات أحد الحلول ، ولكن البديل الذي يسهل التعامل معه في بعض الأحيان هو استخدام شاهد من النوع.

تغيير صفك إلى

class IdToInt a where
  idToInt :: a -> Id a -> Int

instance IdToInt Box where
  idToInt _ s = s

-- if you use this a lot, it's sometimes useful to create type witnesses to use
box = undefined :: Box

-- you can use it like
idToInt box someId

-- or
idToInt someBox (getId someBox)

السؤال الذي تحتاج إلى الإجابة عليه هو ، لأي معين Id, ، هل هناك نوع واحد فقط a يجب أن تظهر مع?وهذا هو ، هل هناك واحد إلى واحد المراسلات بين aق و Id aس?إذا كان الأمر كذلك ، فإن عائلات البيانات هي النهج الصحيح.إذا لم يكن كذلك ، قد تفضل الشاهد.

نصائح أخرى

لا يمكنك ذلك.ستحتاج إلى testFunc :: (IdToInt a) => Id a -> Int.نوع الأسر مفتوحة، لذلك يمكن لأي شخص أن يعلن

giveacodicetagpre.

في أي وقت، ولا تقدم أي وظيفة تحويل.أفضل شيء يجب القيام به هو وضع عائلة النوع في الفصل:

giveacodicetagpre.

ستظل بحاجة إلى السياق، على الرغم من.

لا يمكنك استخدام دالة من النوع IdToInt a => Id a -> Int لأنه لا توجد طريقة لتحديد أي نوع a هو.يوضح المثال التالي هذا.

type family Id a :: *
type instance Id () = Int
type instance Id Char = Int

class IdToInt a where idToInt :: Id a -> Int

instance IdToInt () where idToInt x = x + 1
instance IdToInt Char where idToInt x = x - 1

main = print $ idToInt 1

لأن Id () = Id Char = Int, ، نوع من idToInt في السياق أعلاه هو Int -> Int, ، وهو ما يساوي Id () -> Int و Id Char -> Int.تذكر أنه يتم اختيار طرق التحميل الزائد بناء على النوع.تحدد كلتا مثيلات الفئة idToInt الوظائف التي لها نوع Int -> Int, ، لذلك لا يمكن لمدقق النوع تحديد أيهما يستخدم.

يجب عليك استخدام عائلة بيانات بدلا من عائلة النوع ، وإعلان مثيلات النوع الجديد.

data family Id a :: *
newtype instance Id () = IdUnit Int
newtype instance Id Char = IdChar Int

مع مثيل نوع جديد, Id () و Id Char كلاهما إنتس ، ولكن لديهم أنواع مختلفة.نوع من Id يبلغ المدقق نوع التي مثقلة وظيفة للاستخدام.

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