الشروع في العمل مع لغة البرمجة Elm
نشرت: 2022-03-11عندما اقترح المطور الرئيسي لمشروع مثير للاهتمام ومبتكر للغاية التبديل من AngularJS إلى Elm ، كان أول ما فكرت به هو: لماذا؟
لقد كان لدينا بالفعل تطبيق AngularJS مكتوب بشكل جيد وكان في حالة صلبة ، وتم اختباره جيدًا ، وتم إثباته في الإنتاج. و Angular 4 ، كونها ترقية جديرة بالاهتمام من AngularJS ، كان من الممكن أن تكون خيارًا طبيعيًا لإعادة الكتابة — كذلك يمكن أن يكون React أو Vue. بدت Elm وكأنها لغة غريبة خاصة بمجال معين بالكاد سمع بها الناس.
حسنًا ، كان ذلك قبل أن أعرف أي شيء عن علم. الآن ، مع بعض الخبرة في التعامل معها ، خاصة بعد الانتقال إليها من AngularJS ، أعتقد أنه يمكنني تقديم إجابة على "لماذا".
في هذه المقالة ، سنتعرف على إيجابيات وسلبيات Elm وكيف تتناسب بعض مفاهيمها الغريبة تمامًا مع احتياجات مطور الويب الأمامي. لمزيد من مقالة لغة Elm الشبيهة بالبرنامج التعليمي ، يمكنك إلقاء نظرة على منشور المدونة هذا.
Elm: لغة برمجة وظيفية بحتة
إذا كنت معتادًا على البرمجة في Java أو JavaScript وتشعر أنها طريقة طبيعية لكتابة التعليمات البرمجية ، فإن تعلم Elm يمكن أن يكون مثل السقوط في حفرة الأرانب.
أول شيء ستلاحظه هو التركيب الغريب: لا توجد أقواس ، الكثير من الأسهم والمثلثات.
قد تتعلم كيف تعيش بدون أقواس مجعدة ، ولكن كيف يمكنك تحديد وتداخل كتل من التعليمات البرمجية؟ أو أين هي حلقة for
، أو أي حلقة أخرى ، لهذه المسألة؟ بينما يمكن تعريف النطاق الصريح باستخدام let
block ، لا توجد كتل بالمعنى الكلاسيكي ولا توجد حلقات على الإطلاق.
Elm هي لغة عميل ويب وظيفية بالكامل ومكتوبة بقوة ومتفاعلة وموجهة للأحداث.
قد تبدأ في التساؤل عما إذا كانت البرمجة ممكنة بهذه الطريقة.
في الواقع ، تضاف هذه الصفات لتوفر لك نموذجًا رائعًا للبرمجة وتطوير البرامج الجيدة.
وظيفية بحتة
قد تعتقد أنه باستخدام الإصدار الأحدث من Java أو ECMAScript 6 ، يمكنك القيام ببرمجة وظيفية. لكن هذا مجرد سطح منه.
في لغات البرمجة هذه ، لا يزال بإمكانك الوصول إلى ترسانة من تراكيب اللغة وإغراء اللجوء إلى الأجزاء غير الوظيفية منها. المكان الذي تلاحظ فيه الاختلاف حقًا هو عندما لا يمكنك فعل أي شيء سوى البرمجة الوظيفية. عند هذه النقطة تبدأ في النهاية في الشعور بمدى إمكانية البرمجة الوظيفية الطبيعية.
في علم ، كل شيء تقريبًا عبارة عن وظيفة. اسم السجل هو دالة ، وقيمة نوع الاتحاد هي دالة - تتكون كل دالة من وظائف مطبقة جزئيًا على وسيطاتها. حتى عوامل التشغيل مثل زائد (+) وسالب (-) هي وظائف.
لإعلان أن لغة البرمجة وظيفية بحتة ، بدلاً من وجود مثل هذه التركيبات ، فإن غياب كل شيء آخر له أهمية قصوى. عندها فقط يمكنك البدء في التفكير بطريقة وظيفية بحتة.
تم تصميم Elm على أساس المفاهيم الناضجة للبرمجة الوظيفية ، وهو يشبه اللغات الوظيفية الأخرى مثل Haskell و OCaml.
مكتوب بقوة
إذا كنت تقوم بالبرمجة بلغة Java أو TypeScript ، فأنت تعرف ما يعنيه هذا. يجب أن يكون لكل متغير نوع واحد بالضبط.
توجد بعض الاختلافات بالطبع. كما هو الحال مع TypeScript ، يكون إعلان النوع اختياريًا. إذا لم يكن موجودًا ، فسيتم استنتاجه. لكن لا يوجد نوع "أي".
تدعم Java الأنواع العامة ، ولكن بطريقة أفضل. تمت إضافة العوامل العامة في Java لاحقًا ، لذا فإن الأنواع ليست عامة ما لم يتم تحديد خلاف ذلك. ولاستخدامها نحتاج إلى النحو القبيح <>
.
في Elm ، تكون الأنواع عامة ما لم ينص على خلاف ذلك. لنلقي نظرة على مثال. لنفترض أننا بحاجة إلى طريقة تأخذ قائمة من نوع معين وتعيد رقمًا. في Java سيكون:
public static <T> int numFromList(List<T> list){ return list.size(); }
وفي لغة Elm:
numFromList list = List.length list
على الرغم من أنه اختياري ، أقترح بشدة أن تضيف دائمًا إقرارات النوع. لن يسمح مترجم Elm أبدًا بالعمليات على الأنواع الخاطئة. بالنسبة للإنسان ، من الأسهل بكثير ارتكاب مثل هذا الخطأ ، خاصة أثناء تعلم اللغة. لذلك سيكون البرنامج أعلاه مع التعليقات التوضيحية من النوع:
numFromList: List a -> Int numFromList list = List.length list
قد يبدو من غير المعتاد في البداية الإعلان عن الأنواع في سطر منفصل ، ولكن بعد مرور بعض الوقت تبدأ في الظهور بشكل طبيعي.
لغة عميل الويب
ما يعنيه هذا ببساطة هو أن Elm يترجم إلى JavaScript ، بحيث يمكن للمتصفحات تنفيذها على صفحة ويب.
بالنظر إلى ذلك ، فهي ليست لغة للأغراض العامة مثل Java أو JavaScript مع Node.js ولكنها لغة خاصة بالمجال لكتابة جزء العميل من تطبيقات الويب. أكثر من ذلك ، يتضمن Elm كلاً من كتابة منطق الأعمال (ما يفعله JavaScript) ، والجزء التقديمي (ما يفعله HTML) - كل ذلك بلغة وظيفية واحدة.
كل ذلك يتم بطريقة شبيهة بإطار عمل محدد للغاية ، والتي تسمى The Elm Architecture.
رد الفعل
Elm Architecture هو إطار ويب تفاعلي. يتم عرض أي تغييرات في النماذج على الصفحة مباشرةً ، بدون معالجة DOM صريحة.
بهذه الطريقة ، يشبه Angular أو React. لكن Elm يفعل ذلك أيضًا بطريقته الخاصة. المفتاح لفهم أساسياته يكمن في توقيع view
update
الوظائف:
view : Model -> Html Msg update : Msg -> Model -> Model
لا يقتصر عرض Elm على عرض HTML للنموذج فقط. إنه HTML الذي يمكن أن ينتج رسائل من نوع Msg
، حيث Msg
هو نوع توحيد دقيق تحدده.
يمكن لأي حدث صفحة قياسي إنتاج رسالة. وعند إنشاء رسالة ، يستدعي Elm داخليًا وظيفة التحديث بهذه الرسالة ، والتي تقوم بعد ذلك بتحديث النموذج بناءً على الرسالة والنموذج الحالي ، ويتم عرض النموذج المحدث داخليًا مرة أخرى في طريقة العرض.
الحدث مدفوعة
يشبه Elm الأحداث كثيرًا مثل JavaScript. ولكن على عكس Node.js ، على سبيل المثال ، حيث يتم توفير عمليات الاسترجاعات الفردية للإجراءات غير المتزامنة ، يتم تجميع أحداث Elm في مجموعات منفصلة من الرسائل ، محددة في نوع رسالة واحد. ومثل أي نوع اتحاد ، يمكن أن تكون المعلومات التي تحملها قيم النوع المنفصلة أي شيء.
هناك ثلاثة مصادر للأحداث يمكنها إنتاج رسائل: إجراءات المستخدم في عرض Html
، وتنفيذ الأوامر ، والأحداث الخارجية التي اشتركنا فيها. هذا هو السبب في أن الأنواع الثلاثة ، Html
و Cmd
و Sub
تحتوي على msg
كوسيطة لها. ويجب أن يكون نوع msg
العامة هو نفسه في جميع التعريفات الثلاثة - نفس التعريف المقدم لوظيفة التحديث (في المثال السابق ، كان نوع Msg
، مع حرف M كبير) ، حيث تتم معالجة جميع الرسائل بشكل مركزي.
كود المصدر لمثال واقعي
يمكنك العثور على مثال كامل لتطبيق ويب Elm في مستودع GitHub هذا. على الرغم من بساطتها ، إلا أنها تُظهر معظم الوظائف المستخدمة في برمجة العميل اليومية: استرداد البيانات من نقطة نهاية REST ، وفك تشفير بيانات JSON وتشفيرها ، واستخدام طرق العرض ، والرسائل ، والهياكل الأخرى ، والتواصل مع JavaScript ، وكل ما هو مطلوب للتجميع والحزم كود Elm مع Webpack.
يعرض التطبيق قائمة المستخدمين التي تم استردادها من الخادم.
لتسهيل عملية الإعداد / العرض التوضيحي ، يتم استخدام خادم تطوير Webpack لتعبئة كل شيء ، بما في ذلك Elm ، وخدمة قائمة المستخدمين.
توجد بعض الوظائف في Elm والبعض الآخر في JavaScript. يتم ذلك عن قصد لسبب واحد مهم: إظهار قابلية التشغيل البيني. ربما تريد تجربة Elm للبدء ، أو التبديل تدريجيًا إلى كود JavaScript الحالي ، أو إضافة وظائف جديدة في لغة Elm. من خلال إمكانية التشغيل التفاعلي ، يستمر تطبيقك في العمل مع كل من كود Elm و JavaScript. ربما يكون هذا أسلوبًا أفضل من بدء تشغيل التطبيق بالكامل من البداية في Elm.
يتم أولاً تهيئة جزء Elm في كود المثال ببيانات التكوين من JavaScript ، ثم يتم استرداد قائمة المستخدمين وعرضها بلغة Elm. لنفترض أن لدينا بعض إجراءات المستخدم التي تم تنفيذها بالفعل في JavaScript ، لذا فإن استدعاء إجراء مستخدم في Elm يؤدي فقط إلى إعادة الاتصال إليه.
تستخدم الكود أيضًا بعض المفاهيم والتقنيات الموضحة في القسم التالي.
تطبيق مفاهيم علم
دعونا نستعرض بعض المفاهيم الغريبة للغة برمجة Elm في سيناريوهات العالم الحقيقي.
نوع الاتحاد
هذا هو الذهب الخالص للغة علم. هل تتذكر كل تلك المواقف التي يلزم فيها استخدام بيانات مختلفة هيكليًا باستخدام نفس الخوارزمية؟ من الصعب دائمًا صياغة تلك المواقف.
إليك مثال: تخيل أنك تنشئ ترقيم صفحات لقائمتك. في نهاية كل صفحة ، يجب أن يكون هناك روابط إلى الصفحات السابقة والتالية وجميع الصفحات بأرقامها. كيف تقوم ببنائه للاحتفاظ بالمعلومات الخاصة بالرابط الذي نقر عليه المستخدم؟
يمكننا استخدام عمليات رد نداء متعددة للنقرات السابقة والتالية ورقم الصفحة ، أو يمكننا استخدام واحد أو اثنين من الحقول المنطقية للإشارة إلى ما تم النقر فوقه ، أو إعطاء معنى خاص لقيم عدد صحيح معين ، مثل الأرقام السالبة ، والصفر ، وما إلى ذلك. يمكن لهذه الحلول نمذجة هذا النوع من أحداث المستخدم بالضبط.
في Elm ، الأمر بسيط جدًا. سنحدد نوع الاتحاد:
type NextPage = Prev | Next | ExactPage Int
ونستخدمها كمعامل لإحدى الرسائل:
type Msg = ... | ChangePage NextPage
أخيرًا ، نقوم بتحديث الوظيفة للحصول على case
للتحقق من نوع nextPage
:
update msg model = case msg of ChangePage nextPage -> case nextPage of Prev -> ... Next -> ... ExactPage newPage -> ...
يجعل الأشياء أنيقة للغاية.
إنشاء دالات خريطة متعددة باستخدام <|
تشتمل العديد من الوحدات النمطية على وظيفة map
، مع العديد من المتغيرات لتطبيقها على عدد مختلف من الوسائط. على سبيل المثال ، تحتوي List
على map
، و map2
، ... ، حتى map5
. لكن ماذا لو كانت لدينا دالة تأخذ ست حجج؟ لا يوجد map6
. لكن هناك تقنية للتغلب على ذلك. يستخدم <|
تعمل كمعامل ، ووظائف جزئية ، مع تطبيق بعض الوسيطات على أنها نتائج متوسطة.
للتبسيط ، افترض أن List
تحتوي فقط على map
و map2
، ونريد تطبيق وظيفة تأخذ ثلاث وسيطات في ثلاث قوائم.
إليك كيف يبدو التنفيذ:
map3 foo list1 list2 list3 = let partialResult = List.map2 foo list1 list2 in List.map2 (<|) partialResult list3
لنفترض أننا نريد استخدام foo
، الذي يضاعف وسيطاته العددية ، المعرفة مثل:
foo abc = a * b * c
إذن نتيجة map3 foo [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5]
هي [1,8,27,64,125] : List number
.
دعونا نفكك ما يجري هنا.
أولاً ، في partialResult = List.map2 foo list1 list2
، يتم تطبيق foo
جزئيًا على كل زوج في القائمة list1
list2
2. النتيجة هي [foo 1 1, foo 2 2, foo 3 3, foo 4 4, foo 5 5]
، قائمة بالوظائف التي تأخذ معلمة واحدة (حيث تم تطبيق المعلمتين الأوليين بالفعل) وإرجاع رقم.
التالي في List.map2 (<|) partialResult list3
، إنه في الواقع List.map2 (<|) [foo 1 1, foo 2 2, foo 3 3, foo 4 4, foo 5 5] list3
. لكل زوج من هاتين القائمتين ، نقوم باستدعاء الوظيفة (<|)
. على سبيل المثال ، بالنسبة للزوج الأول ، يكون (<|) (foo 1 1) 1
، وهو نفس foo 1 1 <| 1
foo 1 1 <| 1
، وهو نفس foo 1 1 1
، والذي ينتج 1
. بالنسبة للثانية ، ستكون (<|) (foo 2 2) 2
، وهي foo 2 2 2
، والتي يتم تقييمها إلى 8
، وهكذا.
يمكن أن تكون هذه الطريقة مفيدة بشكل خاص مع وظائف mapN
لفك تشفير كائنات JSON مع العديد من الحقول ، حيث Json.Decode
حتى map8
.
قم بإزالة كافة قيم Nothing من قائمة Maybes
لنفترض أن لدينا قائمة بقيم Maybe
، ونريد استخراج القيم فقط من العناصر التي لها قيمة. على سبيل المثال ، القائمة هي:
list : List (Maybe Int) list = [ Just 1, Nothing, Just 3, Nothing, Nothing, Just 6, Just 7 ]
ونريد الحصول على [1,3,6,7] : List Int
. الحل هو عبارة عن سطر واحد:

List.filterMap identity list
دعونا نرى لماذا يعمل هذا.
يتوقع List.filterMap
أن تكون الوسيطة الأولى دالة (a -> Maybe b)
، يتم تطبيقها على عناصر قائمة مزودة (الوسيطة الثانية) ، ويتم تصفية القائمة الناتجة لحذف جميع قيم Nothing
، ثم القيمة الحقيقية يتم استخراج القيم من Maybe
s.
في حالتنا ، قدمنا identity
، وبالتالي فإن القائمة الناتجة هي مرة أخرى [ Just 1, Nothing, Just 3, Nothing, Nothing, Just 6, Just 7 ]
. بعد تصفيتها ، نحصل على [ Just 1, Just 3, Just 6, Just 7 ]
، وبعد استخلاص القيمة ، تكون [1,3,6,7]
، كما أردنا.
مخصص JSON فك
نظرًا لأن احتياجاتنا في فك تشفير JSON (أو إلغاء التسلسل) تبدأ في تجاوز ما يتم عرضه في وحدة Json.Decode
، فقد نواجه مشكلات في إنشاء وحدات فك ترميز غريبة جديدة. هذا بسبب استدعاء مفككات التشفير هذه من منتصف عملية فك التشفير ، على سبيل المثال ، ضمن طرق Http
، وليس من الواضح دائمًا ما هي المدخلات والمخرجات الخاصة بهم ، خاصةً إذا كان هناك الكثير من الحقول في JSON المزود.
فيما يلي مثالان لإظهار كيفية التعامل مع مثل هذه الحالات.
في الحقل الأول ، لدينا حقلين في JSON الوارد ، a
و b
، للدلالة على جوانب منطقة مستطيلة. لكن في كائن Elm ، نريد فقط تخزين مساحته.
import Json.Decode exposing (..) areaDecoder = map2 (*) (field "a" int) (field "b" int) result = decodeString areaDecoder """{ "a":7,"b":4 }""" -- Ok 28 : Result.Result String Int
يتم فك تشفير الحقول بشكل فردي باستخدام وحدة فك ترميز field int
، ثم يتم توفير كلا القيمتين للوظيفة المتوفرة في map2
. نظرًا لأن الضرب ( *
) هو أيضًا دالة ، ويتطلب معلمتين ، يمكننا فقط استخدامه بهذه الطريقة. الناتج areaDecoder
هو وحدة فك ترميز تقوم بإرجاع نتيجة الوظيفة عند تطبيقها ، في هذه الحالة ، a*b
.
في المثال الثاني ، نحصل على حقل حالة فوضوي ، والذي يمكن أن يكون فارغًا ، أو أي سلسلة تتضمن فارغة ، لكننا نعلم أن العملية نجحت فقط إذا كانت "جيدة". في هذه الحالة ، نريد تخزينها على أنها True
وفي جميع الحالات الأخرى على أنها False
. يبدو جهاز فك التشفير الخاص بنا كما يلي:
okDecoder = nullable string |> andThen (\ms -> case ms of Nothing -> succeed False Just s -> if s == "OK" then succeed True else succeed False )
دعنا نطبقها على بعض JSONs:
decodeString (field "status" okDecoder) """{ "a":7, "status":"OK" }""" -- Ok True decodeString (field "status" okDecoder) """{ "a":7, "status":"NOK" }""" -- Ok False decodeString (field "status" okDecoder) """{ "a":7, "status":null }""" -- Ok False
المفتاح هنا هو في الوظيفة الموردة إلى andThen
، والتي تأخذ نتيجة مفكك تشفير سلسلة سابق (وهي Maybe String
) ، وتحولها إلى كل ما نحتاج إليه ، وترجع النتيجة كمفكك تشفير بمساعدة succeed
.
مفتاح الوجبات الجاهزة
كما يتضح من هذه الأمثلة ، قد لا تكون البرمجة بالطريقة الوظيفية بديهية جدًا لمطوري Java و JavaScript. يستغرق التعود عليه بعض الوقت ، مع الكثير من التجربة والخطأ. للمساعدة في فهمها ، يمكنك استخدام elm-repl
للتمرين والتحقق من أنواع الإرجاع لتعبيراتك.
يحتوي مشروع المثال المرتبط سابقًا في هذه المقالة على العديد من الأمثلة الأخرى لأجهزة فك التشفير وأجهزة التشفير المخصصة والتي قد تساعدك أيضًا على فهمها.
ولكن مع ذلك ، لماذا تختار Elm؟
نظرًا لكونها مختلفة تمامًا عن أطر عمل العميل الأخرى ، فإن لغة Elm ليست بالتأكيد "مكتبة جافا سكريبت أخرى". على هذا النحو ، فإنه يحتوي على الكثير من السمات التي يمكن اعتبارها إيجابية أو سلبية عند مقارنتها بها.
لنبدأ بالجانب الإيجابي أولاً.
برمجة العميل بدون HTML و JavaScript
أخيرًا ، لديك لغة يمكنك من خلالها القيام بكل شيء. لا مزيد من الانفصال والتوليفات المحرجة لخلطهم. لا يوجد إنشاء HTML في JavaScript ولا لغات قوالب مخصصة مع بعض قواعد المنطق التي تم تجريدها.
مع Elm ، لديك بنية واحدة ولغة واحدة في مجدها الكامل.
التوحيد
نظرًا لأن جميع المفاهيم تقريبًا تستند إلى الوظائف ، وبعض الهياكل ، فإن التركيب اللغوي موجز للغاية. لا داعي للقلق إذا تم تحديد طريقة ما على مستوى المثيل أو الفصل الدراسي ، أو إذا كانت مجرد وظيفة. كلها وظائف محددة على مستوى الوحدة. ولا توجد مئات الطرق المختلفة لتكرار القوائم.
في معظم اللغات ، هناك دائمًا هذه الحجة حول ما إذا كانت الشفرة مكتوبة بطريقة اللغة. يجب إتقان الكثير من التعابير الاصطلاحية.
في Elm ، إذا كان يجمع ، فمن المحتمل أن يكون طريقة "Elm". إذا لم يكن كذلك ، حسنًا ، فهو بالتأكيد ليس كذلك.
التعبير
على الرغم من الإيجاز ، فإن بناء جملة Elm معبرة للغاية.
يتم تحقيق ذلك في الغالب من خلال استخدام أنواع الاتحاد وإعلانات النوع الرسمية والأسلوب الوظيفي. كل هذا يلهم استخدام وظائف أصغر. في النهاية ، تحصل على رمز يعد توثيقًا ذاتيًا إلى حد كبير.
لا لاغية
عندما تستخدم Java أو JavaScript لفترة طويلة جدًا ، تصبح null
شيئًا طبيعيًا تمامًا بالنسبة لك - وهو جزء لا مفر منه من البرمجة. وعلى الرغم من أننا نرى باستمرار NullPointerException
s ومختلف TypeError
، ما زلنا لا نعتقد أن المشكلة الحقيقية تكمن في وجود null
. إنه أمر طبيعي جدًا.
يتضح بسرعة بعد مرور بعض الوقت مع Elm. لا يؤدي عدم وجود قيمة null
فقط إلى إعفائنا من رؤية أخطاء مرجعية فارغة لوقت التشغيل مرارًا وتكرارًا ، بل يساعدنا أيضًا في كتابة رمز أفضل من خلال التحديد الواضح والتعامل مع جميع المواقف التي قد لا تكون لدينا فيها القيمة الفعلية ، وبالتالي تقليل الدين الفني أيضًا من خلال عدم تأجيل القيمة null
التعامل حتى ينكسر شيء ما.
الثقة في أنها ستنجح
يمكن إنشاء برامج JavaScript صحيحة نحويًا بسرعة كبيرة. لكن ، هل ستنجح بالفعل؟ حسنًا ، دعنا نرى بعد إعادة تحميل الصفحة واختبارها بدقة.
مع Elm ، العكس هو الصحيح. من خلال التحقق من النوع الثابت وعمليات التحقق من القيمة null
، يحتاج الأمر إلى بعض الوقت للترجمة ، خاصةً عندما يكتب المبتدئ برنامجًا. ولكن بمجرد أن يتم تجميعها ، هناك فرصة جيدة أن تعمل بشكل صحيح.
بسرعة
يمكن أن يكون هذا عاملاً مهمًا عند اختيار إطار عمل العميل. غالبًا ما تكون استجابة تطبيق الويب الشامل أمرًا بالغ الأهمية لتجربة المستخدم ، وبالتالي نجاح المنتج بأكمله. وكما تظهر الاختبارات ، فإن Elm سريع جدًا.
إيجابيات Elm مقابل الأطر التقليدية
توفر معظم أطر عمل الويب التقليدية أدوات قوية لإنشاء تطبيقات الويب. لكن هذه القوة لها ثمن: الهندسة المعمارية المعقدة للغاية مع الكثير من المفاهيم والقواعد المختلفة حول كيفية ووقت استخدامها. يستغرق الأمر الكثير من الوقت لإتقان كل شيء. هناك عناصر تحكم ومكونات وتوجيهات. ثم هناك مراحل التجميع والتكوين ومرحلة التشغيل. وبعد ذلك ، هناك خدمات ومصانع وكل لغة القوالب المخصصة المستخدمة في التوجيهات المقدمة - كل تلك المواقف التي نحتاج فيها إلى استدعاء $scope.$apply()
مباشرة لتحديث الصفحة والمزيد.
من المؤكد أيضًا أن تجميع Elm إلى JavaScript معقد للغاية ، لكن المطور محمي من الاضطرار إلى معرفة كل تفاصيله. فقط اكتب بعض Elm ودع المترجم يقوم بعمله.
ولماذا لا تختار Elm؟
يكفي مدح الدردار. الآن ، دعنا نرى بعض جوانبها غير الرائعة.
توثيق
هذه حقا قضية رئيسية. تفتقر لغة Elm إلى دليل مفصل.
تتصفح الدروس الرسمية اللغة فقط وتترك الكثير من الأسئلة دون إجابة.
المرجع الرسمي API أسوأ. تفتقر الكثير من الوظائف إلى أي نوع من التفسير أو الأمثلة. ثم هناك من لديهم الجملة: "إذا كان هذا محيرًا ، فاعمل من خلال Elm Architecture Tutorial. إنها تساعد حقًا! " ليس أعظم خط تريد رؤيته في مستندات API الرسمية.
نأمل أن يتغير هذا قريبا.
لا أعتقد أنه يمكن اعتماد Elm على نطاق واسع بمثل هذه الوثائق الضعيفة ، خاصة مع الأشخاص القادمين من Java أو JavaScript ، حيث لا تكون هذه المفاهيم والوظائف بديهية على الإطلاق. لفهمها ، هناك حاجة إلى توثيق أفضل بكثير مع الكثير من الأمثلة.
التنسيق والمسافة البيضاء
قد يبدو التخلص من الأقواس أو الأقواس المتعرجة واستخدام المسافة البيضاء للمسافة البادئة أمرًا رائعًا. على سبيل المثال ، يبدو رمز Python أنيقًا جدًا. لكن بالنسبة لمنشئي elm-format
، لم يكن ذلك كافيًا.
مع كل مسافات الأسطر المزدوجة ، والتعبيرات والتعيينات المنقسمة إلى أسطر متعددة ، يبدو كود Elm عموديًا أكثر من كونه أفقيًا. ما يمكن أن يكون سطرًا واحدًا في لغة C القديمة الجيدة يمكن أن يمتد بسهولة إلى أكثر من شاشة واحدة بلغة Elm.
قد يبدو هذا جيدًا إذا تم الدفع لك عن طريق كتابة سطور من التعليمات البرمجية. ولكن ، إذا كنت تريد محاذاة شيء ما مع تعبير بدأ في وقت سابق بـ 150 سطرًا ، حظًا سعيدًا في العثور على المسافة البادئة الصحيحة.
التعامل مع السجلات
من الصعب العمل معهم. صيغة تعديل حقل التسجيلة قبيحة. لا توجد طريقة سهلة لتعديل الحقول المتداخلة أو للإشارة إلى الحقول حسب الاسم بشكل عشوائي. وإذا كنت تستخدم وظائف الموصل بطريقة عامة ، فهناك الكثير من المشاكل في الكتابة الصحيحة.
في JavaScript ، السجل أو الكائن هو الهيكل المركزي الذي يمكن إنشاؤه والوصول إليه وتعديله بعدة طرق. حتى JSON هي مجرد نسخة متسلسلة من السجل. اعتاد المطورون على العمل مع السجلات في برمجة الويب ، لذلك يمكن أن تصبح الصعوبات في التعامل معها في Elm ملحوظة إذا تم استخدامها كهيكل بيانات أساسي.
المزيد من الكتابة
يتطلب Elm كتابة كود أكثر من JavaScript.
لا يوجد تحويل نوع ضمني لعمليات السلسلة والأرقام ، لذلك هناك حاجة إلى الكثير من تحويلات int-float وخاصة استدعاءات toString
، والتي تتطلب بعد ذلك أقواسًا أو رموز تطبيق دالة لمطابقة العدد الصحيح من الوسائط. أيضًا ، تتطلب الدالة Html.text
سلسلة كوسيطة. هناك حاجة إلى الكثير من تعبيرات الحالة ، لكل تلك " Maybe
" ، Results
، والأنواع ، وما إلى ذلك.
السبب الرئيسي لهذا هو نظام النوع الصارم ، ويمكن أن يكون هذا سعرًا عادلًا للدفع.
أجهزة فك التشفير والتشفير JSON
من المجالات التي تبرز فيها الكتابة حقًا معالجة JSON. ما هو مجرد استدعاء JSON.parse()
في JavaScript يمكن أن يمتد لمئات الأسطر في لغة Elm.
بالطبع ، هناك حاجة إلى نوع من التعيين بين هياكل JSON و Elm. لكن الحاجة إلى كتابة كل من وحدات فك التشفير وأجهزة التشفير لنفس القطعة من JSON تمثل مشكلة خطيرة. إذا كانت واجهات برمجة تطبيقات REST الخاصة بك تنقل كائنات تحتوي على مئات الحقول ، فسيكون هذا كثيرًا من العمل.
يتم إحتوائه
لقد رأينا عن Elm ، حان الوقت للإجابة على الأسئلة المعروفة ، والتي ربما تكون قديمة قدم لغات البرمجة نفسها: هل هي أفضل من المنافسة؟ هل يجب أن نستخدمه في مشروعنا؟
قد تكون الإجابة على السؤال الأول ذاتية ، إذ ليست كل أداة مطرقة وليس كل شيء مسمارًا. يمكن أن تتألق Elm وتكون خيارًا أفضل على أطر عميل الويب الأخرى في كثير من الحالات بينما تقصر في حالات أخرى. ولكنه يقدم بعض القيمة الفريدة حقًا التي يمكن أن تجعل تطوير الواجهة الأمامية للويب أكثر أمانًا وأسهل من البدائل.
بالنسبة للسؤال الثاني ، لتجنب إجابة السؤال القديم أيضًا "الأمر يعتمد" ، فإن الإجابة البسيطة هي: نعم. حتى مع جميع العيوب المذكورة ، فإن الثقة التي يمنحك إياها Elm حول صحة برنامجك هي سبب كافٍ لاستخدامه.
الترميز في Elm ممتع أيضًا. إنه منظور جديد تمامًا لأي شخص معتاد على نماذج برمجة الويب "التقليدية".
في الاستخدام الحقيقي ، لا يتعين عليك تبديل تطبيقك بالكامل إلى Elm على الفور أو بدء تطبيق جديد بالكامل فيه. يمكنك الاستفادة من قابلية التشغيل البيني مع JavaScript لتجربتها ، بدءًا من جزء من الواجهة أو بعض الوظائف المكتوبة بلغة Elm. ستكتشف بسرعة ما إذا كان يناسب احتياجاتك ثم توسع استخدامه أو تتركه. ومن يدري ، قد تقع أيضًا في حب عالم برمجة الويب الوظيفية.