يرجى تأكيد أو تصحيح بلدي "الإنجليزية التفسير" من هذا هاسكل البرمجية المتكررة

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

سؤال

أنا C# المطور الذي يعمل من خلال "العالم الحقيقي هاسكل" من أجل فهم حقا البرمجة الوظيفية, وذلك حتى لا تعلم F#, أنا حقا جروك وليس فقط "من كتابة التعليمات البرمجية C# في# F" ، إذا جاز التعبير.

حسنا, اليوم جئت عبر مثال الذي كنت أعتقد أنني فهمت مختلفة 3 مرات فقط ثم نرى شيئا فاتني, تحديث تفسيري ، recurse (و لعنة جدا صدقني).

الآن أعتقد أنني لا أفهم ذلك, وكنت قد كتبت مفصل "الإنجليزية تفسير" أدناه.يمكنك هاسكل معلمو يرجى تأكيد هذا الفهم ، أو نشير إلى ما كنت قد غاب ؟

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

هاسكل البرمجية المتكررة

data List a = Cons a (List a)
              | Nil
              defining Show

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

تحرير:هنا هو بلدي الأصلي (غير صحيحة) "تفسير اللغة الإنجليزية" من المقتطف

  1. أنا تحديد نوع يسمى "قائمة".
  2. قائمة نوع parameterised.أنه يحتوي على نوع واحد المعلمة.
  3. هناك 2 قيمة المنشئات التي يمكن استخدامها لجعل الحالات من القائمة.قيمة واحدة منشئ يسمى "النيل" وغيرها من القيمة منشئ يسمى "سلبيات".
  4. إذا كنت تستخدم "النيل" قيمة منشئ, ثم لا توجد المجالات.
  5. "سلبيات" قيمة منشئ لديه نوع واحد المعلمة.
  6. إذا كنت تستخدم "سلبيات" قيمة منشئ, هناك 2 من المجالات التي يجب توفيرها.أول حقل مطلوب مثيل من القائمة.الثانية الحقل المطلوب هو مثيل.
  7. (لقد أغفل عمدا شيئا عن "تحديد العرض" لأنه ليس جزءا من ما أود التركيز عليه الآن).

تصحيح التفسير سيكون على النحو التالي (التغييرات في جريئة)

  1. أنا تحديد نوع يسمى "قائمة".
  2. قائمة نوع parameterised.ذلك لديه نوع واحد المعلمة.
  3. هناك 2 قيمة المنشئات والتي يمكن استخدامها لجعل الحالات من القائمة.قيمة واحدة منشئ هو ودعا "النيل" وغيرها القيمة منشئ يسمى "سلبيات".
  4. إذا كنت تستخدم "النيل" قيمة منشئ, ثم لا توجد المجالات.

    5.(هذا الخط قد تم حذفه ...أنها ليست دقيقة) "سلبيات" قيمة منشئ لديه نوع واحد المعلمة.

  5. إذا كنت تستخدم "سلبيات" قيمة منشئ, هناك 2 الميادين والتي يجب أن تكون المقدمة.أول حقل مطلوب هو مثيل.الثاني هو حقل مطلوب سبيل المثال من قائمة "من".

  6. (لقد أغفل عمدا شيئا عن "تحديد العرض" لأنه ليس جزءا من ما أود التركيز عليه الآن).

السؤال الذي لا يزال غير واضح

الأولي الالتباس بشأن جزء من قصاصة أن يقرأ "سلبيات على (القائمة ألف)".في الواقع, هذا هو الجزء الذي لا يزال غير واضح بالنسبة لي.

الناس قد أشارت إلى أن كل بند على الخط بعد "سلبيات" المميز هو نوع, لا قيمة.بحيث يعني هذا السطر يقول "سلبيات قيمة منشئ 2 الميادين:واحدة من نوع " أ " و أخرى من نوع 'القائمة من'."

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

على سبيل المثال النظر في هذا GHCI الدورة:

*Main> Cons 0 Nil
Cons 0 Nil
*Main> Cons 1 it
Cons 1 (Cons 0 Nil)
*Main> 

عندما كنت اكتب "سلبيات 0 النيل" ، ويستخدم "سلبيات" قيمة منشئ إنشاء مثيل من القائمة.من 0 ، فإنه يتعلم أن نوع المعلمة "عدد صحيح".حتى الآن أي التباس.

ومع ذلك ، أيضا يحدد القيمة من الحقل الأول من سلبيات هو 0.بعد ذلك يحدد لا شيء عن القيمة من الحقل الثاني ...إلا أن يحدد الحقل الثاني له نوع من قائمة "عدد صحيح".

لذلك سؤالي هو لماذا "أ" في الحقل الأول يعني "نوع من هذا الحقل 'a' و قيمة هذا الحقل هو " أ "" ، بينما "أ" في الحقل الثاني يعني فقط "نوع من هذا الحقل 'قائمة'"?

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

في المقتطف "سلبيات a (قائمة أ)" نحن نقول أن "سلبيات" قيمة منشئ اثنين من المجالات ، و أن أول حقل من النوع " أ " ، و أن الحقل الثاني هو من نوع 'قائمة'.

هذا هو كل ما نقوله! ولا سيما نحن نقول لا شيء عن القيم!هذه هي النقطة الأساسية كنت في عداد المفقودين.

في وقت لاحق, نحن نريد أن إنشاء مثيل باستخدام "سلبيات" قيمة منشئ.نحن نوع هذا إلى مترجم:"سلبيات 0 النيل".هذا صراحة يحكي سلبيات قيمة منشئ لاستخدام 0 قيمة الحقل الأول ، واستخدام النيل كما تكون قيمة الحقل الثاني.

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

شكرا للجميع على الردود المفيدة.و كما قلت, إذا كان أي شيء هو لا يزال خارج ، يرجى من جميع وسائل تقول لي عن ذلك.شكرا

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

المحلول

  • "سلبيات" قيمة منشئ لديه نوع واحد المعلمة.

لا:لقد سبق parametrized عندما أعلن data List a.واحدة فعالة الملكية من هذا هو أنه إذا كان لدي النيل ::قائمة Int, أنا لا يمكن التبادل مع النيل ::قائمة شار.

  • إذا كنت تستخدم "سلبيات" قيمة منشئ, هناك 2 من المجالات التي يجب توفيرها.أول حقل مطلوب مثيل من القائمة.الثانية الحقل المطلوب هو مثيل.

لقد تبادلت:أول حقل مطلوب مثيل من ، الحقل الثاني مثيل من القائمة.

هذا الفصل من العالم الحقيقي هاسكل قد يكون من الفائدة.

شكراهذا هو الفصل الذي أنا عليه الآن.لذا ...عندما يقول قانون "سلبيات a (قائمة أ)" ظننت "سلبيات" على جزء من ذلك مشيرا إلى أن سلبيات قيمة منشئ كان parameterised.أنها لم تتم تغطيتها في بناء الجملة من أجل parameterised أنواع ، لذلك خمنت أن الجملة يجب أن تتطلب إعادة مشيرا إلى "a" إذا كنت تنوي استخدام.ولكن أنت تقول أنه ليس من الضروري ؟ وبالتالي هذا ليس ما أن "a" يعني ؟

لا.بمجرد أن يعلن معلمة في نوع نصل إلى إعادة استخدامها وإلا أن يقول "هذا النوع ينبغي أن تستخدم هناك." انها قليلا مثل a -> b -> a نوع التوقيع:هو parameterizing نوع, ولكن بعد ذلك يجب أن تستخدم نفس كما قيمة الإرجاع.

حسنا, ولكن هذا هو مربكة.يبدو أن أول "أ" يعني "الحقل الأول هو مثيل" ،

كلا, هذا هو لا صحيح.بل يعني فقط أن نوع البيانات parametrizes على بعض نوع.

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

لا, هذا هو أيضا غير صحيح.

وهنا من المفيد على سبيل المثال الجملة التي قد أو قد لا يكون له مثيل من قبل:

foo :: Num a => a -> a

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

وبالتالي ، فإن هذا يوزع إلى اللغة الإنجليزية:

السماح تشير إلى نوع تنفيذ Num typeclass ، ثم توقيع هذه الطريقة هي معلمة واحدة مع نوع و قيمة الإرجاع من نوع

شيء مشابه يحدث مع البيانات.

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

تحرير: في الرد على آخر تحرير.

أعتقد أن التشريح هو أول من دعا.ثم سأتعامل مع الأسئلة الخاصة بك نقطة نقطة.

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

شيء آخر هو أن هاسكل رمز وكثيفة ؛ نوع التوقيع مثل ذلك.لذلك نتوقع أن نرى نفس الرمز استخدامها في سياقات مختلفة.نوع inferencing أيضا يلعب دورا كبيرا هنا.

إذا عودة إلى نوع الخاص بك:

data List a = Cons a (List a)
              | Nil

أنا جزء من هذا إلى عدة قطع:

data قائمة

يعرف هذا الاسم من النوع ، أي معلمات أنواع من أنه سوف يكون في وقت لاحق.ملاحظة أنك سوف ترى فقط يظهر هذا في نوع آخر التوقيعات.

سلبيات a (List a) |
النيل

هذا هو اسم البيانات منشئ. هذا ليس نوع.إلا أننا يمكننا أن نمط المباراة ، علاء:

foo :: List a -> Bool
foo Nil = True

لاحظ كيف أن قائمة النوع في التوقيع و النيل هو كل البيانات منشئ و "الشيء" نحن نمط مباراة.

Cons a (قائمة أ)

هذه هي أنواع من القيم ونحن فتحة في منشئ.سلبيات اثنين من مداخل ، هو واحد من نوع واحد من نوع قائمة.

لذلك سؤالي هو لماذا "أ" في الحقل الأول يعني "نوع من هذا الحقل 'a' و قيمة هذا الحقل هو " أ "" ، بينما "أ" في الحقل الثاني يعني فقط "نوع من هذا الحقل 'قائمة'"?

بسيطة:لا أعتقد أنها لنا تحديد نوع ؛ أعتقد أنه قد هاسكل inferencing نوع من ذلك.علاوة على ذلك, فإن المقاصد, نحن ببساطة التمسك 0-و النيل في القسم الثاني.ثم هاسكل تبدو في مدونة ويفكر:

  • اتسائل ما نوع من سلبيات 0 النيل هو
  • حسنا, سلبيات البيانات منشئ قائمة.أتساءل أي نوع من القائمة أ
  • حسنا, يستخدم في المعلمة الأولى ، لذلك منذ المعلمة الأولى هو الباحث (آخر وتبسيطها ؛ 0 هو فعلا شيء غريب أن typeclassed كما الأسطوانات) ، بحيث يعني هو الأسطوانات
  • حسنا, هذا يعني أيضا أن هذا النوع من النيل قائمة Int, على الرغم من أن هناك لا شيء هناك من شأنها أن الواقع يقول أن

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

نصائح أخرى

عادة ما تفتقر النظافة في جميع أنواع الطرق، ولكن نظرا لأنك تعرف C # اعتقدت أن هذا قد يكون مفيدا.

هذه هي الطريقة التي أود أن أصف List a التعريف في C #، ربما هذا يمسح بعض الأشياء (أو أكثر احتمالا، يربكك أكثر).

class List<A>
{
}

class Nil<A> : List<A>
{
    public Nil() {}
}

class Cons<A> : List<A>
{
    public A Head;
    public List<A> Tail;

    public Cons(A head, List<A> tail)
    {
        this.Head = head;
        this.Tail = tail;
    }
}

كما ترون؛

  • ال List النوع لديه معلمة نوع واحد (<A>),
  • ال Nil منشئ ليس لديه أي معلمات،
  • و ال Cons المنشئ لديه اثنين من المعلمات، قيمة head من النوع A وقيمة tail من النوع List<A>.

الآن، في هاسكل Nil و Cons هي مجرد منشئين ل List a نوع البيانات، في C # هم أيضا أنواع في أنفسهم، لذلك هو المكان الذي فشل فيه التشبيه.

ولكن آمل أن يمنحك هذا بعض الشعور البديهي بما يختلف Aتمثل.

(ويرجى التعليق حول كيفية قيام هذه المقارنة الرهيبة بعدم العدالة لأنواع بيانات Haskell.)

Cons a (List a)

الحقل الأول من السلبيات هو قيمة النوع "a". والثاني هو قيمة النوع"List a"، أي قائمة معلمات مع نفس النوع من المعلمة القائمة الحالية.

5 خطأ، وأقول 6 على النحو التالي لاستبدال كليهما:

سلبيات {1} a {2} (list a) {3} هو منشئ يسمى سلبيات (جزء قبل {1}) للحصول على قيمة قائمة من النوع A (قائمة البيانات جزءا) تحتاج إلى قيمتين: أحد النوع A (الجزء بين {1} و {2}) وواحد من قائمة أنواع (الجزء بين {2} و {3}).

لمساعدتك بمصدر واضح للارتباك: في Haskell بالكاد تضطر إلى إعطاء معلمات نوع صريحة - من النوع الاستدلال ينطني الأنواع من قيمك. لذلك بمعنى ما، نعم، عند تمرير قيمة إلى وظيفة أو منشئ، يمكنك أيضا تحديد نوع، VIZ. نوع القيمة المرة مرت.

نعم بناء جملة البيانات مربكة قليلا، لأنها تجلس الأسماء والأنواع ولا تجعل حقا نصوص التمييز بينهما. على وجه الخصوص، في تعريف المنشئ مثل:

Cons a (List a)

الكلمة الأولى هي اسم المنشئ؛ كل كلمة أخرى هي اسم بعض النوع المحدد. لذلك كلاهما a و List a هي بالفعل في نطاق ( a تم إحضارها إلى النطاق من قبل a في "data List a")، وأنت تقول أن هذه هي أنواع المعلمات. قد يكون دورهم أفضل من خلال ذكر نفس الشيء باستخدام بناء بناء الجملة:

Cons { headL :: a, tailL :: List a }

أي قيمة النوع List Int, إذا تم بناؤه مع Cons منشئ، لديه حقلان: Int و List Int. وبعد إذا تم بناء مع Nil, لا يوجد لديه حقول.

عندما اكتب "Cons 0 Nil"، يستخدم"Cons"سعر المنشئ لإنشاء مثيل قائمة. من 0، يتعلق الأمر بأن المعلمة النوع"Integer". حتى الآن، لا تشويش.

ومع ذلك، فإنه يحدد أيضا أن قيمة المجال الأول من السلبيات هو 0. ومع ذلك، فإنه يحدد شيئا عن قيمة الحقل الثاني ... يحدد فقط أن الحقل الثاني لديه نوع من "قائمة عدد صحيح".

لا، فإنه يحدد أن قيمة المجال الثاني Nil. وبعد بالنظر إلى تعريفك، Nil هي قيمة من النوع List a. وبعد لذلك هو كذلك Cons 0 Nil. وبعد و في Cons 1 it قيمة الحقل الثاني it; ؛ بمعنى آخر، Cons 0 Nil. وبعد هذا هو بالضبط ما يظهر التشغيل:Cons 1 (Cons 0 Nil).

نظرت إلى سؤالك المحرر.

عندما أقوم بإنشاء مثيلات باستخدام منشئ قيمة السلبيات، هذه المثيلات "تفسير" الأول "الأول" كما معنى "ضع القيمة التي تم تمريرها هنا.

في "سلبيات (قائمة A)"، كلاهما "A" و "قائمة" هي أنواع. لا أفهم ما يجب عليه "القيمة" معها.

عندما أكتب "سلبيات 0 nil"، فإنه يستخدم منشئ قيمة "سلبيات" لإنشاء مثيل قائمة. من 0، يتعلق الأمر بمعلمة النوع "عدد صحيح". حتى الآن، لا ارتباك.

ومع ذلك، فإنه يحدد أيضا أن قيمة المجال الأول من السلبيات هو 0. ومع ذلك، فإنه يحدد شيئا عن قيمة الحقل الثاني ... يحدد فقط أن الحقل الثاني لديه نوع من "قائمة عدد صحيح".

قيمة الحقل الثاني هو Nil.

لذلك سؤالي هو، لماذا يعني "A" في الحقل الأول "نوع هذا الحقل"، وقيمة هذا الحقل "A"، في حين أن "A" في الحقل الثاني يعني فقط "النوع من هذا المجال هو "قائمة"؟

"A" في المجال الأول يعني "نوع هذا الحقل هو" ". "قائمة A" في المجال الثاني تعني "نوع هذا الحقل" قائمة "". في حالة "سلبيات 0 NIL" أعلاه، "A" يستنتج أن تكون "عدد صحيح". لذلك "سلبيات (قائمة أ)" تصبح "سلبيات سلبيات (عدد صحيح القائمة)". 0 هي قيمة عدد صحيح من النوع. nil هو قيمة نوع "عدد صحيح القائمة".

قيمة هذا الحقل هو "A"

أنا لا أفهم ما تقصد بهذا. "A" هو متغير نوع؛ ماذا يجب أن تفعل مع القيم؟

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

خاصية "مضحكة" أخرى في Haskell هي أنه لا يتمتع بوضوح (أو ضمنيا) بتقييم الحجج إلى وظيفة، حتى لو كانت هذه الحجة بين قوسين. وبعد اسمحوا لي أن أذكر أنه بطريقة مختلفة قليلا: لا تقيم وظائف Haskell الوسائط بين قوسين قبل الحجج الأخرى. يتم وضع الحجج بين قوسين لأغراض تجمع فقط، وليس لديهم تقييمهم "أولا". تعيين Haskell الحجج إلى ("ينطبق") وظيفة بأعلى أعلى من أي عملية أخرى - حتى أعلى من تطبيق دالة ضمنية لأحد الحجج الخاصة به. هذا هو السبب في Cons المنشئ لديه عامة حول الحجة الثانية، (List a) - لإخبار المحول البرمجي ذلك Cons لديه اثنين من الحجج وليس ثلاثة. وبعد الأقواس هي للتجميع فقط، وليس للأسبقية!

كما هو موضع مستوى جانبي، كن حذرا مع الأنواع في F #. منذ F # لها جذوره في مل، تحتوي أنواعها المعلمة على المعلمات في الجبهة - int list, ، ليس (List Int) في الظهر! Haskell يفعل ذلك في الاتجاه الآخر، لأنه بنفس الطريقة التي تعمل بها haskell - أولا الوظيفة، ثم الحجج إلى الوظيفة. يشجع ذلك على نمط الاستخدام المشترك، ويوضح سبب رسملة أنواع Haskell و Brances Oriense - لتذكيرك أنك تتعامل مع شيء متعلق بالنوع / الفصل.

حسنا انتهيت؛ شكرا على السماح لي بوضع هذا النص الحائط الضخم على الممتلكات الخاصة بك ...

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