انتخاب موتور الگوی: مشکل قدرتمندتر

در ادامه با موضوع موتورهای الگو ، می خواهم افکار خود را در مورد قدرت موتورهای الگو و نحوه ارتباط آن با قدرت انتزاع در برنامه نویسی.
ابتدا ، اجازه دهید طبقه بندی موتورهای الگو را که در پست قبلی خود ذکر کرده ام ، نگاهی بیندازیم:
- غیر منطقی: موتور الگو هیچ منطقی در الگوی اجازه نمی دهد. تمام منطق قبل از رسیدن به موتور الگوی ، از محتوای متغیر ، داده های ما استفاده می شود. یک مثال معمولی سبیل است.
- وابسته به منطق: موتور الگو به شما امکان می دهد برخی از منطق را در الگو تعریف کنید ، مانند نه تنها چه چیزی ، بلکه چه زمانی و نحوه نمایش آن. یک مثال معمولی Jinja2 است.
- منطقی: چنین موتورهای الگو به شما امکان می دهد هرگونه منطق دلخواه خود را در الگوی تعریف کنید ، با این امکان که حتی کد را در الگوی اجرا کنید. یک مثال Sweave در R است که اجازه می دهد کد R را در قالب های لاتکس تعبیه کنید.
کدام موتور الگوی را انتخاب کنید؟ غیر منطقی به نظر می رسد ، خوب ، کمتر. منطقی ارزش بیشتری برای پول به ما می دهد – این قدرتمندتر است.
اما آیا ما واقعاً می خواهیم قدرتمندتر؟
قدرت را به من نشان دهید
بیایید دو امضای عملکرد زیر را در نظر بگیریم ، هر دو در مورد آرایه های Typescript تعریف شده اند:
type MapFn<T, U> = (arr: T[], fn: (x: T) => U) => U[];
type ReduceFn<T, U> = (arr: T[], fn: (acc: U, x: T) => U, base: U) => U;
اولین عملکرد ، مشابه با Array.prototype.map
، یک آرایه و یک عملکرد را می گیرد و عملکرد را برای هر عنصر از آرایه اعمال می کند و یک آرایه جدید را با نتایج برنامه های عملکردی باز می گرداند:
mapFn([1, 2, 3], (x) => x * 2); // [2, 4, 6]
عملکرد دوم ، مشابه با Array.prototype.reduce
، یک آرایه ، یک تابع و یک مقدار پایه را می گیرد و عملکرد را برای هر عنصر آرایه اعمال می کند و نتیجه را در مقدار پایه جمع می کند:
reduceFn([1, 2, 3], (acc, x) => acc + x, 0); // 6
کدام یک عملکرد قدرتمندتر است؟ از نظر عملی ، reduceFn
حداقل به دو دلیل به طور قابل توجهی قدرتمندتر است:
-
این می تواند تغییر کند ساختار از داده ها به یک ساختار متفاوت. در مثال بالا ، ما مجموعه ای از اعداد را به یک عدد واحد تبدیل کردیم. ما می توانیم مجموعه ای از اعداد را به یک شی تبدیل کنیم:
reduceFn([1, 2, 3], (acc, x) => ({ ...acc, [x]: x * 2 }), {}); // { 1: 2, 2: 4, 3: 6 }
-
ما می توانیم تعریف کنیم
mapFn
عملکرد از نظرreduceFn
:const mapFn: MapFn<T, U> = (arr: T[], fn: (x: T) => U) => reduceFn(arr, (acc, x) => [...acc, fn(x)], []);
اگر تنها با یکی از این دو کارکرد به یک جزیره فرستاده شویم ، احتمالاً انتخاب می کنیم reduceFn
، زیرا بیشتر چاقوی ارتش سوئیس است.
شما قدرت بیشتری می خواهید؟ از آنچه می خواهید مراقب باشید. بگذارید نگاهی دقیق تر به معنای برنامه نویسی داشته باشیم.
خمیردندان در مقابل چاقو
خوشبختانه (یا نه) ، ما رابینسون نیستیم بلکه برنامه نویسان هستیم. ما می خواهیم اطمینان حاصل کنیم که ما نه تنها یک مشکل را حل می کنیم بلکه این کار را به گونه ای انجام می دهیم که راه حل قابل حفظ ، خواندنی و قابل درک باشد.
در نظر گرفتن Functor
وت Monad
کلاسهای نوع در هاکل. به ما دو انتزاع داده می شود:
fmap :: Functor f => (a -> b) -> f a -> f b
bind :: Monad m => (a -> m b) -> m a -> m b
اولین مورد یک عملکرد و یک را مصرف می کند Functor
، و عملکرد را در درون از Functor
، بازگشت همان Functor
با یک مقدار جدید در داخل. ساختار حفظ شده است بدون عملکرد حتی دانستن هر چیزی در مورد ساختار.
با این حال ، در حالت دوم ، عملکرد نه تنها در مورد ساختار می داند بلکه باید آن را نیز حفظ کند. در اینجا یک نمونه بارزتر برای انتزاع فوق وجود دارد:
toothpick :: (a -> b) -> IO a -> IO b
knife :: (a -> IO b) -> IO a -> IO b
اولا ، در هر دو مورد به ما داده می شود IO
عمل IO
است Monad
بشر
من به عنوان یک برنامه نویس همکار که برای روابط عمومی شما بررسی می کند ، ترجیح می دهم ببینم toothpick
در کد شما knife
بدیهی است که قدرتمندتر است ، اما همچنین پیچیده تر است.
تنها اطمینان لازم برای toothpick
عملکرد خوب این است که بدانید عملکرد به آن منتقل شده است toothpick
است عملکرد کل، یعنی خطا نخواهد کرد. اجازه ندهید IO
شما را احمق کنید: همه Monad
است Functor
و این toothpick
دقیقاً شبیه است یا حتی هست fmap
بشر
اما knife
اجازه می دهد خودسرانه IO
عملیات و امضای آن محدود نمی شود که این عملیات چیست. در عمل ، این بدان معنی است که درب برای بسیاری از موارد باز است که می توانند اشتباه پیش بروند. حتی اگر کد امروز ایمن باشد ، هیچ تضمینی وجود ندارد که کسی فردا انگشت خود را قطع نکند.
این یکی از دلایلی است که توصیه های مشترک در هاسکل انتخاب است کمترین انتزاعی که کار را انجام می دهدبشر من این توصیه را ابتدا به دلیل خرد و سپس به دلایل فنی می بینم.
بنابراین ، غذای آماده ما این است:
اگر دلیل خوبی ندارید (و بیمه نامه های لازم) برای انتخاب انتزاع قدرتمندتر ، با قدرت کمتری بروید.
بازگشت به موتورهای الگو
اکنون ، اجازه دهید ما به موتورهای الگوی خود برگردیم. ما دیده ایم که غیر منطقی لزوماً بد نیست ، و منطقی لزوما خوب نیست همه اینها به متن بستگی دارد.
در بیشتر موارد ، با این حال ، می توانیم فرض کنیم که غیر منطقی موتور الگو به اندازه کافی خوب برای ما کار خواهد کرد. با توجه به تیمی از برنامه نویسان ، طراحان و تحلیلگران داده ، هنوز هم می تواند کاملاً عملی باشد:
- طراح و برنامه نویس Frontend می توانند بدون نگرانی در مورد منطق ، روی الگوی کار کنند. آنها یک ساختار خاص را برای داده ها فرض می کنند و بر روی ارائه تمرکز می کنند.
- تحلیلگر داده ها الگوی و حتی ارائه را تا حدی نادیده می گیرد ، اما فقط برای تعریف داده هایی که می تواند گزارش را نشان دهد ، ساختار خاصی را ارائه می دهد.
- برنامه نویس باطن فقط به تهیه داده های گزارش و الگوی اهمیت می دهد ، داده های گزارش را به داده های الگوی تبدیل می کند و الگوی را با داده ها ارائه می دهد.
چه چیزی در این مورد خوب است؟
- تعامل بین افراد بیشتر در مورد مفهوم و کمتر در مورد اجرای است.
- به عنوان مثال ، این ارتباطات بر روی قراردادهای واضح ، یعنی الگوی و تعاریف داده ها ، مانند به شکل طرح های JSON ، تحقق می یابد.
- ساده تر ، غیر منطقی Engine Template می تواند بسیار ساده تر از یک برنامه قدرتمندتر ، مانند یک برنامه وب تک صفحه ای برای طراح ، یک ابزار CLI برای برنامه نویس Frontend و تحلیلگر داده ها مستقر شود ، که در عوض منجر به تکرار سریعتر و حلقه های بازخورد خواهد شد.
- ساده تر ، غیر منطقی موتورهای الگو معمولاً به زبان های برنامه نویسی متعدد منتقل می شوند و به برنامه نویس پس زمینه انعطاف پذیری اضافی می دهند تا زبان ، چارچوب ، استقرار و میزبانی را انتخاب کنند.
- تولید مثل و بازپرداخت الگوی و همچنین کل ساختار تیم بسیار ساده تر است.
پایان
اگر کسی از من بخواهد موتور الگوی را انتخاب کنم ، من احتمالاً با یک غیر منطقی یکی ، اگر دلیل خاصی وجود نداشته باشد و یک برنامه نگهداری بسیار خوب که نیاز به یک را توجیه می کند وابسته به منطق یک و برای منطقی یکی ، من نمی توانم به یک دلیل واحد برای استفاده از آن فکر کنم وابسته به منطق یکی ، به جز نمونه سازی سریع ، و شاید برای برنامه نویسی با سواد خاص دامنه مانند Rmarkdown ، نوت بوک های Jupyter و غیره.
بنابراین ، اگر من مجبور باشم یکی از آنها را انتخاب کنم ، احتمالاً به دنبال سبیل می روم ، و در صورت لزوم یک پردازنده JSON مانند JQ به عنوان چسب.
این به من می دهد آرامش، اگر نه شادی ، در انتخاب عبارات منظم بر روی یک زبان تورینگ کامل.
من فکر می کنم یک پست وبلاگ دیگر به منظور بحث در مورد تجارت استفاده از استفاده است زبانهای برنامه نویسی خاص ، دامنه ، دامنه در مقابل زبانهای برنامه نویسی ضروری ، هدف کلیبشر