سؤال

إذا تم تعريف بعض الأيام على النحو التالي:

data SomeType = X {myBool :: Bool} 
                | Y {myString :: String} 
                | Z {myString :: String}

وسوف أقوم بتحديث X تعسفي، تعتمد على نوعه على النحو التالي:

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST (Y s) = (Y "newString")
changeST (Z s) = (Z "newString")

الخط الثالث والرابع يفعلان نفس الشيء، يقومون بتحديث السلسلة في النوع المحدد. هل هناك أي طريقة تحل محل هذين السطرين من قبل واحد، على سبيل المثال. عن طريق تعيين نوع إلى متغير؟

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

المحلول

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

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST st = st { myString = "newString" }

هذا إرجاع نفس القديس كما حجتها، ولكن مع قيمة myString استبدال الحقل. إنها واحدة من ميزات الحقول الرائعة التي يمكنك القيام بذلك دون رعاية منشئ البيانات، طالما أنها واحدة من منشئ البيانات التي تستخدم myString.

نصائح أخرى

يمكنك استخدام الخردة الخاص بك المرجع لهذا.

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics

data SomeType
  = X { myBool :: Bool }
  | Y { myString :: String }
  | Z { myString :: String }
  deriving (Data, Typeable)

changeST :: SomeType -> SomeType
changeST = everywhere (mkT (const True)) . everywhere (mkT (const "newString"))

هذه changeST التغييرات كل داخلي String في هيكلك ل "newString" وكل Bool ل True.

أنا أفضل حل دان، لكن حراس النمط في GHC (Standard in Haskell 2010) هي بديل أنيق لاقتراح مايكل:

{-# LANGUAGE PatternGuards #-}
changeST :: SomeType -> SomeType
changeST x | X _ <- x = X True
           | Y _ <- x = Y newString
           | Z _ <- x = Z newString
  where    newString = "newString"

تعاريفك الثلاث changeST منفصلة عن بعضهم البعض، وبالتالي فإن الإجابة القصيرة هي "لا". ومع ذلك، هناك طريقتين على الأقل يمكنك القيام بذلك.

نمط تطابق كل من Y و Z منشئون في وقت واحد:

يمكنك الجمع بين التعريف الثاني والثالث عن طريق جعل نمطك مطابقة أكثر عام:

changeST x = x { myString = "newString"}

هذا يخلق نسخة جديدة من x, ، سواء كان Y أو أ Z, ، استبدال عضو السلسلة. عليك أن تكون حذرا عند القيام بذلك. إذا قمت بإعادة تسمية حقل سلسلة لاحقا Z, على سبيل المثال، سوف تحصل على حالات فشل مطابقة نمط وقت التشغيل عند الاتصال بالتغيير مع Z جدال.

استخدام التعبير حالة:

إذا كنت تجمع بين تعريفاتك الثلاثة في واحدة، يمكنك مشاركة البيانات بينهما.

changeST :: SomeType -> SomeType
changeST x = case x of
    X _ -> X True
    Y _ -> Y newString
    Z _ -> Z newString
  where
    newString = "newString"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top