سؤال

عند النوع X يعرف ب:

data X = 
    X { sVal :: String } |
    I { iVal :: Int } |
    B { bVal :: Bool }

وأريد Int داخل X القيمة، إذا كان هناك واحد، خلاف ذلك صفر.

returnInt :: X -> Int

كيف يمكنني تحديد نوع X حجة ل returnInt هو؟

هل كانت مفيدة؟

المحلول

فقط لتوضيح نقطة هنا، اسمحوا لي بإعادة كتابة نوع البيانات الخاص بك لتجنب الغموض في معنى X:

data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}

في هذا التعريف، لا توجد أنواع X، I و B. س، أنا و ب منشئون يخلقون قيمة من النوع Sometype وبعد لاحظ ما يحدث عندما تسأل GHCI ما هو نوع أي قيمة مصنوعة من منشئ النوع هذه:

*Main> :t (I 5)
(I 5) :: Sometype 

*Main> :t (B False)
(B False) :: Sometype

انهم ينتمون الى نفس النوع!

تماما كما يمكنك استخدام X، I و B لبناء أنواع، يمكنك استخدام نمط المطابقة لتنفصل النوع، مثل القيام به في الإجابات الأخرى أعلاه:

returnInt :: SomeType -> Int 
returnInt (I x) = x        -- if the pattern matches (I x) then return x
returnInt _  = error "I need an integer value, you moron"  -- throw an error otherwise

فقط تذكر أن مطابقة النمط يحدث بالترتيب: إذا كانت القيمة تطابق النموذج في بعض السطر، فإن الأنماط الموجودة في الأسطر الموجودة أدناه لن يتم تنفيذها.

لاحظ أنه عند تحديد نوعك كما فعلت، استخدم ما يسمى بناء جملة سجل (انظر فقط هنا: http://en.wikibooks.org/wiki/haskell/more_on_datatypes. )، حصلت على وظائف من هذا القبيل مجانا !!

حاول النظر في نوع القيم، على سبيل المثال:

*Main> :t myInt
myInt :: SomeType -> Int

وانظر إلى ما تفعله هذه الوظيفة:

*Main> myInt (I 5)
5

*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt

هذا هو بالضبط سلوك returnInt أعلاه المعرفة. رسالة الخطأ الغريبة تخبرك فقط أن الوظيفة لا تعرف كيفية التعامل مع عضو من النوع في وقت عام لا تتطابق (I x).

إذا حددت نوعك باستخدام بناء الجملة الأكثر شيوعا:

data SomeType2 = X String | I Int | B Bool

ثم تفقد تلك الوظائف السارية لطيفة.

رسائل الخطأ تنهي تنفيذ البرنامج. هذا مزعج في بعض الأحيان. إذا كنت بحاجة إلى سلوك أكثر أمانا لوظائفك إجابة GBACON هي طريقة القيام بذلك فقط. تعرف على Maybe a اكتب واستخدامها للتعامل مع هذا النوع من الحساب الذي يحتاج إلى إرجاع بعض القيمة أو إرجاع أي شيء (جرب هذا: http://en.wikibooks.org/wiki/haskell/hierarchical_libraries/maybe. ).

نصائح أخرى

استخدام مطابقة نمط.

returnInt :: X -> Int
returnInt (I x) = x
returnInt _     = 0

استخدم تعريفا أكثر مرونة لجميع ممكن X القيم:

returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing

ثم يمكنك استخدام maybe بالنسبة للتخلف عن التخلف عنها، قد تكون هناك قيمة صالحة (هذا يعرف باسم مشكلة semippredicate.):

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1

في المقابل، وظائف جزئية استثناءات وقت تشغيل المخاطر:

*Main> let returnInt (I i) = i
*Main> :t returnInt
returnInt :: X -> Int
*Main> returnInt (B True)
*** Exception: <interactive>:1:4-22: Non-exhaustive patterns in function returnInt

إذا كنت تشعر بالضفادع حقا، فيمكنك استخدامها MonadPlus

returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero

للحصول على المزيد من المرونة:

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> returnInt (I 123) `mplus` returnInt (I 456) :: [Int]
[123,456]

إعطاء وظيفة مثل هذا:

returnInt :: X -> Int
returnInt x = {- some integer -}

...نوع من x دائما X. وبعد ما تهتم به هو ما إذا كان x يستخدم X, I أو B نوع المنشئ.

استخدم نمط المطابقة لإخبار الفرق:

returnInt :: X -> Int
returnInt (X _) = error "needed an Int, got a String"
returnInt (I { iVal = n }) = n
returnInt (B _) = error "needed an Int, got a Bool"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top