سؤال

بدأت أفهم كيف forall الكلمات الرئيسية المستخدمة في ما يسمى "الوجودية أنواع" مثل هذا:

data ShowBox = forall s. Show s => SB s

هذا هو مجموعة فرعية فقط, ومع ذلك, كيف forall يستخدم وأنا ببساطة لا يمكن الإقتناع استخدامه في مثل هذه الأمور:

runST :: forall a. (forall s. ST s a) -> a

أو يشرح لماذا هذه مختلفة:

foo :: (forall a. a -> a) -> (Char, Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))

أو كله RankNTypes الاشياء...

أنا أميل إلى تفضيل واضحة خالية من المصطلحات الإنجليزية بدلا من أنواع اللغة التي هي طبيعية في بيئة أكاديمية.معظم التفسيرات محاولة قراءة هذا (تلك التي لا يمكن أن تجد من خلال محركات البحث) لدينا هذه المشاكل:

  1. أنهم غير مكتملة.يشرحون جزء واحد من استخدام هذه الكلمة (مثل "الوجودية أنواع") الذي يجعلني أشعر بالسعادة حتى قرأت التعليمات البرمجية التي تستخدم في طريقة مختلفة تماما (مثل runST, foo و bar أعلاه).
  2. إنهم المكتظ مع الافتراضات التي قرأت آخر في أي فرع من الرياضيات المنفصلة, نظرية الفئة أو الجبر المجرد شعبية هذا الأسبوع.(إذا أنا لم أقرأ عبارة "استشارة الورق مهما كان لمزيد من التفاصيل حول تنفيذ" مرة أخرى ، سيكون قريبا جدا.)
  3. أنها كتبت في الطرق التي كثيرا ما تتحول حتى مفاهيم بسيطة في tortuously الملتوية و كسر قواعد اللغة وعلم الدلالة.

لذا...

على أن السؤال الفعلي.هل يستطيع أحد أن يفسر تماما forall الكلمة واضحة في سهل الانجليزية (أو إذا كان موجودا في مكان ما ، أشر إلى هذا تفسيرا واضحا التي اشتقت) أن لا نفترض أنا رياضيات غارق في المصطلحات?


التعديل لإضافة:

كان هناك اثنين تبرز إجابات من أعلى نوعية منها أدناه ، ولكن للأسف أنا يمكن أن تختار واحدة فقط أفضل. نورمان الجواب كان مفصلة و مفيدة, شرح الأمور بطريقة أظهرت بعض الأسس النظرية من forall و في نفس الوقت تظهر بعض الآثار العملية المترتبة على ذلك. yairchu الجواب يغطي مساحة لا أحد آخر ذكر (راقب نوع المتغيرات) ويتضح من جميع المفاهيم مع رمز GHCi الدورة.كان من الممكن لتحديد كل أفضل ، وأود أن.للأسف لا أستطيع و على كل الإجابات عن كثب ، لقد قررت أن yairchu قليلا حواف نورمان بسبب توضيحية رمز وتعلق التفسير.هذا هو قليلا غير عادلة ، ومع ذلك ، لأنه حقا لا حاجة كل الإجابات على فهم هذا إلى النقطة التي forall لا تترك لي خافت شعور بالرهبة عندما أرى ذلك في نوع التوقيع.

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

المحلول

لنبدأ بمثال رمز:

foob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b
foob postProcess onNothin onJust mval =
    postProcess val
    where
        val :: b
        val = maybe onNothin onJust mval

لا يتم تجميع هذا الرمز (خطأ في بناء الجملة) في Haskell 98. يتطلب امتدادًا لدعم forall الكلمة الرئيسية.

في الأساس ، هناك 3 مختلف الاستخدامات الشائعة ل forall الكلمة الرئيسية (أو على الأقل هكذا يبدو) ، ولكل منها امتداد هاسكل الخاص به: ScopedTypeVariables, RankNTypes/Rank2Types, ExistentialQuantification.

لا يحصل الكود أعلاه على خطأ في بناء الجملة مع أي من الممكّن ScopedTypeVariables تمكين.

متغيرات النوع المنحدر:

تساعد متغيرات النوع المنتشر على تحديد أنواع الكود في الداخل where شروط. يجعل b في val :: b نفس الشيء مثل b في foob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b.

نقطة مربكة: قد تسمع ذلك عندما تحذف forall من نوع ما لا يزال هناك ضمنيا هناك. ((من إجابة نورمان: "عادةً ما تحذف هذه اللغات من أنواع الأشكال المتعددة"). هذا الادعاء صحيح ، لكن يشير إلى الاستخدامات الأخرى forall, وليس إلى ScopedTypeVariables استعمال.

نوع الرتبة N-types:

لنبدأ بذلك mayb :: b -> (a -> b) -> Maybe a -> b يعادل mayb :: forall a b. b -> (a -> b) -> Maybe a -> b, إلا الى متى ScopedTypeVariables تم تمكين.

هذا يعني أنه يعمل لكل a و b.

دعنا نقول أنك تريد أن تفعل شيئًا كهذا.

ghci> let putInList x = [x]
ghci> liftTup putInList (5, "Blah")
([5], ["Blah"])

ما الذي يجب أن يكون نوع هذا liftTup؟ إنه liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b). لمعرفة السبب ، دعنا نحاول ترميزه:

ghci> let liftTup liftFunc (a, b) = (liftFunc a, liftFunc b)
ghci> liftTup (\x -> [x]) (5, "Hello")
    No instance for (Num [Char])
    ...
ghci> -- huh?
ghci> :t liftTup
liftTup :: (t -> t1) -> (t, t) -> (t1, t1)

"حسنًا .. لماذا يستنتج GHC أن Tuple يجب أن يحتوي على اثنين من نفس النوع؟ دعنا نخبره أنه لا يجب أن يكونوا"

-- test.hs
liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)

ghci> :l test.hs
    Couldnt match expected type 'x' against inferred type 'b'
    ...

همم. لذا هنا لا يسمح لنا GHC بطلب liftFunc على v لان v :: b و liftFunc يريد x. نريد حقًا أن تحصل وظيفتنا على وظيفة تقبل أي شيء ممكن x!

{-# LANGUAGE RankNTypes #-}
liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)

لذلك ليس كذلك liftTup هذا يعمل للجميع x, ، إنها الوظيفة التي تحصل عليها.

الكمية الوجودية:

دعونا نستخدم مثالًا:

-- test.hs
{-# LANGUAGE ExistentialQuantification #-}
data EQList = forall a. EQList [a]
eqListLen :: EQList -> Int
eqListLen (EQList x) = length x

ghci> :l test.hs
ghci> eqListLen $ EQList ["Hello", "World"]
2

كيف يختلف ذلك عن الأنواع من رتبة N؟

ghci> :set -XRankNTypes
ghci> length (["Hello", "World"] :: forall a. [a])
    Couldnt match expected type 'a' against inferred type '[Char]'
    ...

مع الأنواع من رتبة N ، forall a يعني أن تعبيرك يجب أن يناسب كل شيء ممكن aس. فمثلا:

ghci> length ([] :: forall a. [a])
0

قائمة فارغة تعمل كقائمة من أي نوع.

لذلك مع التكيف الوجودي ، forallS في data التعريفات تعني أن القيمة الموجودة يستطيع كن من أي نوع مناسب ، وليس ذلك يجب كن من الكل أنواع مناسبة.

نصائح أخرى

هل يمكن لأحد تماما اشرح الكلمة الرئيسية forall باللغة الإنجليزية الواضحة والواضحة؟

رقم. (حسنا ، ربما دون ستيوارت يمكن.)

فيما يلي الحواجز أمام شرح بسيط وواضح أو forall:

  • إنه مقياس كمي. لديك أن يكون لديك القليل من المنطق على الأقل (حساب التفاضل والتكامل الأصلي) لمشاهدة كمية عالمية أو وجودية. إذا لم تكن قد رأيت حساب التفاضل والتكامل المسند أو لم تكن مرتاحًا للتكيف (ورأيت الطلاب خلال اختبارات التأهيل الدكتوراه غير المرتاحين) ، فلا يوجد تفسير سهل لـ forall.

  • انه يكتب الكمي. إذا لم تر النظام و وحصلت على بعض التدريبات في كتابة أنواع الأشكال المتعددة ، ستجد forall مربك. التجربة مع Haskell أو ML ليست كافية ، لأن هذه اللغات عادة ما تتجاهل forall من أنواع الأشكال. (في رأيي ، هذا خطأ في تصميم اللغة.)

  • في هاسكل على وجه الخصوص ، forall يستخدم بطرق أجد مربكًا. (أنا لست منظراً نوعًا ، لكن عملي يجلبني على اتصال مع كثير من نظرية النوع ، وأنا مرتاح جدًا لها.) بالنسبة لي ، المصدر الرئيسي للارتباك هو ذلك forall يستخدم لتشفير نوع أفضل أن أفضّل الكتابة معه exists. يبررها جزءًا صعبًا من التماثل الذي يتضمن الكميات والسهام ، وفي كل مرة أريد أن أفهمها ، يجب أن أبحث عن الأشياء وأعد التماثل بنفسي.

    إذا لم تكن مرتاحًا لفكرة نوع التماثل ، أو إذا لم يكن لديك أي ممارسة تفكر forall ذاهب إلى stymie لك.

  • بينما المفهوم العام ل forall هو نفسه دائمًا (الربط لتقديم متغير نوع) ، يمكن أن تختلف تفاصيل الاستخدامات المختلفة بشكل كبير. اللغة الإنجليزية غير الرسمية ليست أداة جيدة جدًا لشرح الاختلافات. لفهم حقًا ما يحدث ، تحتاج إلى بعض الرياضيات. في هذه الحالة ، يمكن العثور على الرياضيات ذات الصلة في نص بنيامين بيرس التمهيدي الأنواع ولغات البرمجة, ، وهو كتاب جيد جدا.

بالنسبة للأمثلة الخاصة بك ،

  • runST ينبغي اجعل رأسك يؤلمني. نادراً ما توجد أنواع ذات رتبة أعلى (تنقلب على يسار السهم) في البرية. أشجعك على قراءة الورقة التي قدمت runST: "خيوط الحالة الوظيفية كسول". هذه ورقة جيدة حقًا ، وسوف تمنحك حدس أفضل بكثير لنوع من runST على وجه الخصوص والأنواع ذات الرتبة الأعلى بشكل عام. يأخذ التفسير عدة صفحات ، لقد تم إنجازه جيدًا ، ولن أحاول تكثيفها هنا.

  • انصح

    foo :: (forall a. a -> a) -> (Char,Bool)
    bar :: forall a. ((a -> a) -> (Char, Bool))
    

    إذا اتصلت bar, ، يمكنني ببساطة اختيار أي نوع a التي أحبها ، ويمكنني تمرير وظيفة من النوع a لكتابة a. على سبيل المثال ، يمكنني تمرير الوظيفة (+1) أو الوظيفة reverse. يمكنك التفكير في forall بقول "أحصل على اختيار النوع الآن". (الكلمة الفنية لاختيار النوع إنشاء مثيل.)

    القيود المفروضة على الاتصال foo أكثر صرامة: الوسيطة foo يجب تكون وظيفة متعددة الأشكال. مع هذا النوع ، الوظائف الوحيدة التي يمكنني نقلها إليها foo نكون id أو وظيفة تتباين أو أخطاء دائمًا ، مثل undefined. السبب هو ذلك مع foo, ، ال forall هو على يسار السهم ، لذلك كمتصل foo لا يمكنني اختيار ما a هو - الحي هو تطبيق من foo هذا يحصل على اختيار ما a هو. لان forall هو على يسار السهم ، وليس فوق السهم كما في bar, ، يحدث التثبيت في جسم الوظيفة بدلاً من موقع الاتصال.

ملخص: أ مكتمل شرح forall الكلمة الرئيسية تتطلب الرياضيات ويمكن فهمها فقط من قبل شخص درس الرياضيات. حتى التفسيرات الجزئية يصعب فهمها بدون رياضيات. ولكن ربما تساعد تفسيراتي الجزئية غير المثيرة قليلاً. اذهب اقرأ Launchbury و Peyton Jones On runST!


إضافة: Jargon "أعلاه" ، "أدناه" ، "إلى يسار". هذه لا علاقة لها بـ نص الطرق المكتوبة وكل ما يتعلق بأشجار الخلاصة التجريدية. في بناء الجملة المجردة ، أ forall يأخذ اسم متغير النوع ، ثم هناك نوع كامل "أدناه" forall. يأخذ السهم نوعين (وسيطة ونوع النتيجة) ويشكل نوعًا جديدًا (نوع الوظيفة). نوع الوسيطة "على يسار" السهم ؛ إنه الطفل الأيسر للسهم في شجرة التزامات التجريدية.

أمثلة:

  • في forall a . [a] -> [a], ، فورال فوق السهم. ما هو على يسار السهم [a].

  • في

    forall n f e x . (forall e x . n e x -> f -> Fact x f) 
                  -> Block n e x -> f -> Fact x f
    

    سيتم تسمية النوع في الأقواس "Forall على يسار السهم". (أنا أستخدم أنواعًا من هذا القبيل في محسن أعمل عليه.)

إجابتي الأصلية:

هل يمكن لأي شخص أن يشرح الكلمة الرئيسية بشكل كامل باللغة الإنجليزية الواضحة البسيطة

كما يشير نورمان ، من الصعب جدًا تقديم شرح إنجليزي واضح ومباشر لمصطلح فني من نظرية النوع. كلنا نحاول رغم ذلك.

لا يوجد سوى شيء واحد فقط يجب تذكره حول "forall": يربط الأنواع ببعض النطاق. بمجرد أن تفهم ذلك ، كل شيء سهل إلى حد ما. إنه ما يعادل "lambda" (أو شكل من أشكال "Let") على مستوى النوع - يستخدم نورمان رامزي فكرة "اليسار"/"أعلاه" لنقل هذا المفهوم نفسه للنطاق في إجابته الممتازة.

معظم استخدامات "forall" بسيطة للغاية ، ويمكنك العثور عليها مقدمة في دليل مستخدمي GHC ، S7.8.، خصوصا الممتازة S7.8.5 على أشكال متداخلة من "forall".

في Haskell ، عادة ما نترك الموثق لأنواع ، عندما يكون النوع Quanitized ، مثل ذلك:

length :: forall a. [a] -> Int

يعادل:

length :: [a] -> Int

هذا هو.

نظرًا لأنه يمكنك ربط متغيرات النوع الآن ببعض النطاق ، يمكنك الحصول على نطاقات أخرى غير المستوى العلوي ("كمية عالمية") ، مثل مثالك الأول ، حيث يكون متغير النوع مرئيًا فقط داخل بنية البيانات. وهذا يسمح لأنواع مخفية ("أنواع الوجودية"). أو يمكننا الحصول التعشيش التعسفي من الارتباطات ("الأنواع رتبة N").

لفهم أنظمة النوع العميقة ، ستحتاج إلى تعلم بعض المصطلحات. هذه هي طبيعة علوم الكمبيوتر. ومع ذلك ، يجب أن تكون الاستخدامات البسيطة ، كما هو أعلاه ، قادرة على الحصول على حدسي ، من خلال القياس مع "دع" على مستوى القيمة. مقدمة رائعة Launchbury و Peyton Jones.

إنهم مليئون بكثافة مع الافتراضات التي قرأتها الأحدث في أي فرع من فروع الرياضيات المنفصلة أو نظرية الفئة أو الجبر المجردة تحظى بشعبية هذا الأسبوع. (إذا لم أقرأ أبدًا عبارة "استشر الورقة مهما كانت تفاصيل التنفيذ" مرة أخرى ، فسيكون ذلك في وقت مبكر.)

إيه ، وماذا عن منطق الدرجة الأولى البسيطة؟ forall من الواضح تمامًا في إشارة إلى القياس الكمي العالمي, وفي هذا السياق المصطلح الوجودية أكثر منطقية أيضًا ، على الرغم من أنه سيكون أقل حرجًا إذا كان هناك exists الكلمة الرئيسية. ما إذا كان القياس الكمي عالميًا أو الوجودي بشكل فعال يعتمد على وضع الكمي بالنسبة إلى حيث يتم استخدام المتغيرات على أي جانب من سهم الوظيفة وكل شيء مربك بعض الشيء.

لذا ، إذا لم يساعد ذلك ، أو إذا كنت لا تحب المنطق الرمزي ، فمن منظور البرمجة الأكثر وظيفية ، يمكنك التفكير في متغيرات النوع على أنها مجرد (ضمني) يكتب المعلمات إلى الوظيفة. تتم كتابة وظائف أخذ المعلمات في هذا المعنى بشكل تقليدي باستخدام Lambda رأس المال لأي سبب من الأسباب ، والتي سأكتبها هنا باسم /\.

لذلك ، فكر في id وظيفة:

id :: forall a. a -> a
id x = x

يمكننا إعادة كتابتها على أنها lambdas ، ونقل "المعلمة النوع" من توقيع النوع وإضافة التعليقات التوضيحية نوعًا مضمّنًا:

id = /\a -> (\x -> x) :: a -> a

هذا هو نفس الشيء الذي تم فعله const:

const = /\a b -> (\x y -> x) :: a -> b -> a

بحيث bar قد تكون الوظيفة شيئًا من هذا القبيل:

bar = /\a -> (\f -> ('t', True)) :: (a -> a) -> (Char, Bool)

لاحظ أن نوع الوظيفة المعطاة ل bar كحجة تعتمد على barمعلمة نوع. فكر إذا كان لديك شيء مثل هذا بدلاً من ذلك:

bar2 = /\a -> (\f -> (f 't', True)) :: (a -> a) -> (Char, Bool)

هنا bar2 يتم تطبيق الوظيفة على شيء من النوع Char, ، لذلك العطاء bar2 أي معلمة نوع غير ذلك Char سوف يسبب خطأ في النوع.

من ناحية أخرى ، إليك ما foo قد تبدو مثل:

foo = (\f -> (f Char 't', f Bool True))

على عكس bar, foo لا تأخذ في الواقع أي معلمات النوع على الإطلاق! يستغرق وظيفة بحد ذاتها يأخذ معلمة نوع ، ثم يطبق هذه الوظيفة على اثنين مختلف الأنواع.

لذلك عندما ترى أ forall في توقيع النوع ، فقط فكر في الأمر على أنه أ تعبير Lambda لتوقيعات النوع. تماما مثل lambdas العادية ، نطاق forall يمتد إلى أقصى حد ممكن إلى اليمين ، وربما إلى إرفاق قوسين ، ومثل المتغيرات المرتبطة في lambda العادية ، ومتغيرات النوع ملزمة forall هي فقط في نطاق داخل التعبير الكمي.


ما بعد النص: ربما قد تتساءل-الآن أننا نفكر في وظائف أخذ معلمات النوع ، لماذا لا يمكننا أن نفعل شيئًا أكثر إثارة للاهتمام مع تلك المعلمات بدلاً من وضعها في توقيع النوع؟ الجواب هو أننا نستطيع!

الوظيفة التي تضع متغيرات النوع مع تسمية وإرجاع نوع جديد اكتب مُنشئًا, ، والتي يمكنك كتابة شيء مثل هذا:

Either = /\a b -> ...

لكننا بحاجة إلى تدوين جديد تمامًا ، لأن الطريقة التي يتم بها كتابة هذا النوع ، مثل Either a b, ، توحي بالفعل بـ "تطبيق الوظيفة Either لهذه المعلمات ".

من ناحية أخرى ، فإن وظيفة "تطابق الأنماط" على معلمات النوع ، وإرجاع قيم مختلفة لأنواع مختلفة ، هي أ طريقة فئة النوع. توسع طفيف لي /\ بناء الجملة أعلاه يشير إلى شيء مثل هذا:

fmap = /\ f a b -> case f of
    Maybe -> (\g x -> case x of
        Just y -> Just b g y
        Nothing -> Nothing b) :: (a -> b) -> Maybe a -> Maybe b
    [] -> (\g x -> case x of
        (y:ys) -> g y : fmap [] a b g ys 
        []     -> [] b) :: (a -> b) -> [a] -> [b]

أنا شخصياً أعتقد أنني أفضل بناء الجملة الفعلي لـ Haskell ...

وظيفة "نمط يطابق" معلمات نوعها وتُرجع نوعًا تعسفيًا ، النوع الموجود هو أ اكتب الأسرة أو التبعية الوظيفية-في الحالة السابقة ، يبدو بالفعل الكثير مثل تعريف الوظيفة.

فيما يلي تفسير سريع وقذر بعبارات واضحة من المحتمل أن تكون على دراية به بالفعل.

ال forall الكلمة الرئيسية تستخدم حقا فقط بطريقة واحدة في هاسكل. هذا يعني دائمًا نفس الشيء عندما تراه.

القياس الكمي العالمي

أ نوع كمي عالمي هو نوع من النموذج forall a. f a. يمكن اعتبار قيمة هذا النوع AS وظيفة هذا يأخذ يكتب a كحجة لها ويعيد أ القيمة من النوع f a. باستثناء أنه في هاسكل ، يتم تمرير هذه الوسائط النوعية ضمنيًا بواسطة نظام النوع. يجب أن تمنحك هذه "الوظيفة" نفس القيمة بغض النظر عن النوع الذي يتلقاه ، وبالتالي فإن القيمة متعدد الأشكال.

على سبيل المثال ، فكر في النوع forall a. [a]. قيمة هذا النوع تأخذ نوعًا آخر a ويعيدك قائمة العناصر من نفس النوع a. لا يوجد سوى تطبيق واحد ممكن ، بالطبع. يجب أن تعطيك القائمة الفارغة بسبب a يمكن أن يكون أي نوع على الإطلاق. القائمة الفارغة هي قيمة القائمة الوحيدة التي تكون متعددة الأشكال في نوع العنصر (لأنه لا يوجد لديه عناصر).

أو النوع forall a. a -> a. يوفر المتصل لهذه الوظيفة نوعًا a وقيمة النوع a. ثم يتعين على التنفيذ إرجاع قيمة من نفس النوع a. لا يوجد سوى تطبيق واحد ممكن مرة أخرى. يجب أن تعيد نفس القيمة التي تم إعطاؤها.

الكمية الوجودية

و نوع كمية وجودية سيكون له النموذج exists a. f a, ، إذا دعم هاسكل هذا التدوين. يمكن اعتبار قيمة هذا النوع AS زوج (أو "منتج") يتكون من نوع a وقيمة النوع f a.

على سبيل المثال ، إذا كان لديك قيمة النوع exists a. [a], ، لديك قائمة من العناصر من نوع ما. يمكن أن يكون أي نوع ، ولكن حتى لو كنت لا تعرف ما هو هناك الكثير الذي يمكنك القيام به لمثل هذه القائمة. يمكنك عكس ذلك ، أو يمكنك حساب عدد العناصر ، أو تنفيذ أي عملية قائمة أخرى لا تعتمد على نوع العناصر.

حسنًا ، انتظر دقيقة. لماذا يستخدم هاسكل forall للدلالة على نوع "وجودي" مثل ما يلي؟

data ShowBox = forall s. Show s => SB s

يمكن أن يكون مربكًا ، لكنه يصف حقًا نوع منشئ البيانات SB:

SB :: forall s. Show s => s -> ShowBox

بمجرد بناءها ، يمكنك التفكير في قيمة النوع ShowBox كما يتكون من شيئين. إنه نوع s جنبا إلى جنب مع قيمة النوع s. بمعنى آخر ، إنها قيمة لنوع كمي موجود. ShowBox يمكن أن تتم كتابتها حقًا exists s. Show s => s, ، إذا دعم هاسكل هذا التدوين.

runST والأصدقاء

بالنظر إلى ذلك ، كيف تختلف هذه؟

foo :: (forall a. a -> a) -> (Char,Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))

لنأخذ أولاً bar. يستغرق نوعا a ودالة النوع a -> a, وتنتج قيمة النوع (Char, Bool). يمكننا أن نختار Int كما a ومنحها وظيفة من النوع Int -> Int فمثلا. ولكن foo مختلف. يتطلب تنفيذ foo تكون قادرًا على تمرير أي نوع يريده إلى الوظيفة التي نقدمها. لذا فإن الوظيفة الوحيدة التي يمكن أن نعطيها بشكل معقول id.

يجب أن نكون قادرين الآن على معالجة معنى نوع runST:

runST :: forall a. (forall s. ST s a) -> a

لذا runST يجب أن تكون قادرة على إنتاج قيمة النوع a, ، بغض النظر عن النوع الذي نعطيه a. للقيام بذلك ، يحتاج إلى حجة من النوع forall s. ST s a التي تحت غطاء محرك السيارة مجرد وظيفة من النوع forall s. s -> (a, s). ثم يجب أن تكون هذه الوظيفة قادرة على إنتاج قيمة النوع (a, s) بغض النظر عن نوع تنفيذ runST يقرر إعطاء s.

طيب ، ماذا في ذلك؟ الفائدة هي أن هذا يضع قيدًا على المتصل runST في هذا النوع a لا يمكن إشراك النوع s على الاطلاق. لا يمكنك اجتيازها قيمة النوع ST s [s], ، فمثلا. ما يعنيه ذلك في الممارسة العملية هو أن تنفيذ runST مجاني لأداء طفرة مع قيمة النوع s. يضمن نظام النوع أن هذه الطفرة محلية لتنفيذ runST.

نوع من runST هو مثال على أ النوع 2 متعدد الأشكال لأن نوع حجته يحتوي على ملف forall الكمي. نوع من foo أعلاه هو أيضا من المرتبة 2. نوع متعدد الأشكال ، مثل bar, ، هو المرتبة الأولى ، لكنه يصبح المرتبة الثانية إذا كانت أنواع الحجج مطلوبة لتكون متعددة الأشكال ، بذاتها الخاصة forall الكمي. وإذا أخذت الوظيفة حجج المرتبة الثانية ، فإن نوعها هو المرتبة 3 ، وهكذا. بشكل عام ، وهو نوع يأخذ حججًا متعددة الأشكال من المرتبة n لديه رتبة n + 1.

السبب في وجود استخدامات مختلفة لهذه الكلمة الرئيسية هو أنها تستخدم بالفعل في امتدادات نظام مختلفة على الأقل: أنواع الرتبة العليا ، والوجودية.

من الأفضل أن تقرأ عن هذين الأمرين وفهمهما بشكل منفصل ، بدلاً من محاولة الحصول على شرح لماذا "forall" هو جزء مناسب من بناء الجملة في كلاهما في نفس الوقت.

هل يستطيع أحد أن يفسر تماما forall الكلمة واضحة في سهل الانجليزية (أو إذا كان موجودا في مكان ما ، أشر إلى هذا تفسيرا واضحا التي اشتقت) أن لا نفترض أنا رياضيات غارق في المصطلحات?

أنا ذاهب إلى محاولة شرح فقط معنى وربما تطبيق forall في سياق هاسكل و نوع الأنظمة.

ولكن قبل أن نفهم أن وأود أن توجهك إلى الوصول للغاية وجميل الكلام من قبل Runar Bjarnason بعنوان "القيود تحرير, تقييد الحريات".الحديث هو الكامل من الأمثلة في العالم الحقيقي حالات الاستخدام فضلا عن أمثلة في سكالا لدعم هذا البيان ، على الرغم من أنه لا يذكر forall.سوف أحاول أن أشرح forall منظور أدناه.

                CONSTRAINTS LIBERATE, LIBERTIES CONSTRAIN

من المهم جدا لهضم نعتقد أن هذا البيان إلى المضي قدما في الشرح التالي, لذا ندعوكم لمشاهدة هذا الحديث(على الأقل أجزاء منه).

الآن مثال شائع جدا, تبين التعبير من هاسكل نوع النظام هل هذا نوع التوقيع:

foo :: a -> a

ويقال أن تعطى هذا النوع التوقيع هناك وظيفة واحدة فقط التي يمكن أن تلبي هذا النوع و هذا هو identity وظيفة أو ما هو أكثر من المعروف شعبيا id.

في المراحل الأولى من لي التعلم هاسكل, لطالما تساءلت أدناه الوظائف:

foo 5 = 6

foo True = False

كلاهما يفي فوق نوع التوقيع ثم لماذا هاسكل الناس يزعمون أنه هو id وحده الذي يرضي نوع التوقيع ؟

ذلك لأن هناك ضمني forall مخبأة في نوع التوقيع.النوع الفعلي هو:

id :: forall a. a -> a

حتى الآن دعونا نعود إلى بيان: القيود تحرير, تقييد الحريات

ترجمة ذلك إلى نوع نظام هذا البيان يصبح:

قيدا على مستوى النوع ، يصبح الحرية في مصطلح المستوى

و

الحرية في مستوى النوع ، يصبح عائقا في مصطلح المستوى


دعونا نحاول أن نثبت البيان الأول:

قيدا على مستوى النوع..

لذلك وضع قيدا على نوع التوقيع

foo :: (Num a) => a -> a

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

foo 5 = 6
foo 4 = 2
foo 7 = 9
...

نفسه يمكن ملاحظتها من خلال تقييد a مع أي typeclass الخ

حتى الآن ما نوع هذا التوقيع: foo :: (Num a) => a -> a يترجم إلى:

∃a , st a -> a, ∀a ∈ Num

هذا هو المعروف باسم الوجودية الكمي الذي يترجم إلى هناك بعض الحالات من a التي دالة عند تغذية شيء من نوع a إرجاع شيء من نفس نوع تلك الحالات تنتمي جميعها إلى مجموعة من الأرقام.

ومن ثم يمكننا أن نرى إضافة القيد(أن a يجب أن تنتمي إلى مجموعة من الأرقام) ، وتحرر مصطلح مستوى لديك عدة تطبيقات ممكنة.


يأتي الآن إلى البيان الثاني و الذي يحمل في الواقع تفسير forall:

الحرية في مستوى النوع ، يصبح عائقا في مصطلح المستوى

حتى الآن دعونا نحرر وظيفة في مستوى نوع:

foo :: forall a. a -> a

الآن هذا يترجم إلى:

∀a , a -> a

وهو ما يعني أن تنفيذ هذا النوع ينبغي أن يكون توقيع هذا a -> a لجميع الظروف.

حتى الآن يبدأ هذا تحد لنا في الأجل المستوى.لم يعد بإمكاننا كتابة

foo 5 = 7

لأن هذا التنفيذ لا يرضي إذا وضعنا a كما Bool. a يمكن أن يكون Char أو [Char] أو العرف نوع البيانات.تحت جميع الظروف يجب أن يعود شيء من نوع مماثل.هذه الحرية على مستوى النوع هو ما يعرف باسم العالمي الكمي و الوظيفة الوحيدة التي يمكن أن تلبي هذه

foo a = a

وهو المعروف identity وظيفة


ومن ثم forall هو liberty على مستوى النوع الذي الفعلية الغرض من ذلك هو constrain مصطلح مستوى معين التنفيذ.

كيف الوجودية الوجودية؟

مع التكيف الوجودي ، forallS في data التعريفات تعني أن القيمة الموجودة يستطيع كن من أي نوع مناسب ، وليس ذلك يجب كن من الكل أنواع مناسبة. - إجابة Yachiru

شرح لماذا forall في data التعاريف متماثلة (exists a. a) (Pseudo-Haskell) يمكن العثور عليها في ويكيبوكس "Haskell/أنواع كمية الوجودية".

فيما يلي ملخص موجز حرفيًا:

data T = forall a. MkT a -- an existential datatype
MkT :: forall a. a -> T -- the type of the existential constructor

عند مطابقة الأنماط/التفكيك MkT x, ، ما هو نوع x?

foo (MkT x) = ... -- -- what is the type of x?

x يمكن أن يكون أي نوع (كما هو مذكور في forall) ، وهكذا هو نوع:

x :: exists a. a -- (pseudo-Haskell)

لذلك ، فإن ما يلي متماثل:

data T = forall a. MkT a -- an existential datatype
data T = MkT (exists a. a) -- (pseudo-Haskell)

forall يعني forall

تفسيري البسيط لكل هذا ، هو "ذلك"forall يعني حقًا "للجميع". تمييز مهم لجعله هو تأثير forall على ال تعريف مقابل الوظيفة طلب.

أ forall يعني تعريف يجب أن تكون القيمة أو الوظيفة متعددة الأشكال.

إذا كان الشيء الذي يتم تعريفه هو متعدد الأشكال القيمة, ، ثم يعني أن القيمة يجب أن تكون صالحة للجميع مناسبة a, ، وهو مقيد للغاية.

إذا كان الشيء الذي يتم تعريفه هو متعدد الأشكال وظيفة, ، ثم يعني أن الوظيفة يجب أن تكون صالحة للجميع a, ، هذا ليس مقيدًا لأنه لمجرد أن الوظيفة تعدد الأشكال لا يعني أن المعلمة مُطبَّق يجب أن تكون متعددة الأشكال. هذا هو ، إذا كانت الوظيفة صالحة للجميع a, ، ثم على العكس أي متكافئ a يمكن ان يكون مُطبَّق إلى الوظيفة. ومع ذلك ، لا يمكن اختيار نوع المعلمة إلا مرة واحدة في تعريف الوظيفة.

اذا كان forall هو داخل نوع المعلمة الوظيفة (أي ، أ Rank2Type) ثم يعني مُطبَّق يجب أن تكون المعلمة حقا متعدد الأشكال ، أن تكون متسقة مع فكرة forall يعني تعريف هو متعدد الأشكال. في هذه الحالة ، يمكن اختيار نوع المعلمة أكثر من مرة في تعريف الوظيفة ("ويتم اختياره من خلال تنفيذ الوظيفة" ، كما أشار نورمان)

لذلك ، السبب وراء الوجودية data التعريفات تسمح أي a هو أن مُنشئ البيانات هو متعدد الأشكال وظيفة:

MkT :: forall a. a -> T

نوع من mkt :: a -> *

وهو ما يعني أي a قد يتم تطبيقها على الوظيفة. على عكس ، على سبيل المثال ، متعدد الأشكال القيمة:

valueT :: forall a. [a]

نوع من Valuet :: a

وهو ما يعني أن ال تعريف من Valuet يجب أن تكون متعددة الأشكال. في هذه الحالة، valueT يمكن تعريفها على أنها قائمة فارغة [] من جميع الأنواع.

[] :: [t]

اختلافات

على الرغم من المعنى ل forall متسق في ExistentialQuantification و RankNType, ، الوجوديين لديه فرق منذ data يمكن استخدام مُنشئ في مطابقة الأنماط. كما هو موثق في دليل مستخدم GHC:

عند مطابقة الأنماط ، تقدم كل نمط مطابقة نوعًا جديدًا متميزًا لكل متغير نوع الوجود. لا يمكن توحيد هذه الأنواع مع أي نوع آخر ، ولا يمكنهم الهروب من نطاق تطابق النمط.

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