برنامه نویسی

ماشین حساب نوع بی فایده در تایپ اسکریپت

Summarize this content to 400 words in Persian Lang
زمان یکی از بی فایده ترین چیزهایی است که تا به حال ساخته ام – چیزی فراتر از عقل، جایی که منطق از عقلانی بودن باز می ایستد و خلأ واقعیت است. زمان آن رسیده است که یک ماشین حساب با استفاده از انواع Typescript ایجاد کنید.

در ابتدا در وبلاگ من، 5 اکتبر 2021 ارسال شد: https://aamulumi.info/Dev/The-Useless-Type-Calculator-in-Typescript

چند روز پیش یاد بحثی با یکی از دوستانم در مورد سیستم های کامل تورینگ افتادم. ما مقاله ویکی‌پدیا را در مورد این موضوع بررسی کردیم و متوجه شدیم که بسیاری از چیزها (مانند بازی‌ها) با تورینگ کامل هستند. بنابراین بله، Minecraft کامل Turing است، Factorio نیز، قلعه کوتوله نیز، و به نظر می رسد که Habbo Hotel و Magic: The Gathering (بله، بازی کارتی) نیز تورینگ کامل هستند.

همچنین در جایی متوجه شدیم که نوع سیستم Typescript Turing-complete است. با این دانش، تصمیم گرفتم شروع به توسعه چیزی کنم که چیزی را تغییر ندهد: یک ماشین حساب فقط با انواع Typescript.

بله. این یکی از احمقانه ترین ایده هایی است که برای مدتی به ذهنم رسید. اما این یک تمرین سرگرم کننده است که می توانید برای اثبات مهارت های خود در تایپ کردن همه چیز انجام دهید.

قوانین

اگر می خواهید ماشین حساب را انجام دهید، قوانین “بازی” در اینجا آمده است (اگر بتوانیم این را یک بازی بنامیم):

شما باید فقط با دو نوع شروع کنید: BZero (برای Boolean Zero) و BOne (برای Boolean One).

type BZero = false;
type BOne = true;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما فقط می توانید از انواع استفاده کنید. بدون رابط، بدون enum، فقط انواع.
شما باید چهار عملیات اساسی ریاضی (با انواع) را محاسبه کنید: جمع، تفریق، ضرب و تقسیم. شما همچنین می توانید ماژول اضافه کنید.
این کد باید کار کند:

// Equivalent of (6 + 6 * (1 + 2)) / (6 – 2) = 6
type StrangeOperation = Divide<
Add<Multiply<Six, Add<One, Two>>, Six>,
Subtract<Six, Two>
>;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با توجه به نحوه پیاده سازی ماشین حساب، از نوع دیگری استفاده می کنم Result برای خواندن نتیجه:

type OpResult = Result<StrangeOperation>;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این نوع در قوانین کاملا اختیاری است. اما در پایان محاسبات باید یک نوع عدد دقیق داشته باشید. به عنوان مثال، شما باید داشته باشید:

type OpResult = 6;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و در اینجا شما بروید! وقت آن است که شما کدنویسی کنید!

بله، بهتر است راه حل را بخوانید، اینطور نیست؟

راه حل

مفهوم

در ابتدا، من جستجو می کنم که راه های بدست آوردن یک نوع عدد از یک نوع در Typescript چیست. شما باید عملیات پایه خود را تغییر دهید BZero و BOne به Zero و One شماره اگر این را می دانید

من چیزی را بر اساس شاخص های آرایه امتحان کردم، اما راهی برای بدست آوردن عدد وجود نداشت. بنابراین من متوجه شدم که تاپل های Typescript دارای یک هستند length دارایی و از 3.0 با تاپل های متغیر کار می کند. با این اطلاعات، من شروع به نوشتن یک ماشین حساب بر اساس Tuples کردم.

type TypeNumber = Array<any>;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اولین انواعی که ما نیاز داریم عبارتند از Zero و One بر اساس تاپل ها به این ترتیب، یک نوع شرطی ساده می نویسم که یک تاپل را با تعداد عناصر معادل عددی که توصیف می کند، برمی گرداند. به عنوان مثال:

type ToTypeNumber<A> = A extends true ? [true] : [];

type Zero = ToTypeNumber<BZero>;
type One = ToTypeNumber<BOne>;

// Result
type Zero = [];
type One = [true];

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به این ترتیب به یک تایپ برای خواندن طول تاپل نیاز داریم تا عدد نوع مورد نظر را بدست آوریم.

type Result<A extends TypeNumber> = A[“length”];

// Example
type C = Result<One>;

// Result
type C = 1;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

عملیات 1: اضافه کردن

با این تصور، Add type به لطف Typescript 4.0 ساده ترین عملیات برای پیاده سازی است. ما باید دو تاپل را به هم متصل کنیم و یک را انجام دادیم Add نوع

type Add<A extends TypeNumber, B extends TypeNumber> = […A, …B];

// Example
type Two = Add<One, One>;
type TwoResult = Result<Two>;
type Four = Add<Two, Two>;
type FourResult = Result<Four>;

// Result
type Two = [true, true];
type TwoResult = 2;
type Four = [true, true, true, true];
type FourResult = 4;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

عملیات 2: تفریق

راه سخت

حالا، سرگرمی شروع می شود.

ما باید به محاسبات پشت تفریق فکر کنیم. پس بیایید به مدرسه ابتدایی برگردیم.

من 6 بادکنک دارم. من 4 تا بادکنک به مانو میدم. الان 2 بادکنک باقی مانده است.

از نظر تاپل ها، می توانیم مشکل را با این توضیح دهیم:

type MyBalloons = [true, true, true, true, true, true];
type NewManuBalloons = [true, true, true, true];
type NewMyBalloons = [true, true];

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای اجرای تفریق، هر عنصر را می‌گیرم MyBalloons یکی یکی و بررسی کنید که آیا هر عنصر در آن وجود دارد یا خیر NewManuBalloons. وقتی من در این لحظه می رسم دیگر عنصری در آن وجود ندارد NewManuBallooons، من شروع به افزایش یک متغیر می کنم که نتیجه آن خواهد بود.

اما یک مشکل وجود دارد: به نظر می رسد یک حلقه است. چگونه می توانیم به یک حلقه در Typescript برسیم؟

پاسخ در اینجا استفاده از نوع بازگشتی است. و با یک شرط، می توانیم این کار را با یک نوع شرطی بازگشتی انجام دهیم. این هم کد:

type Subtract<
A extends TypeNumber,
B extends TypeNumber,
Res extends TypeNumber = [] > = A extends [boolean, …infer H] ? B extends [boolean, …infer J] ? Subtract<H, J, Res>
: Subtract<H, B, Add<Res, One>>
: Res;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اوه بله، نکته دیگری وجود دارد: من از استنتاج نوع برای حذف عناصر یک تاپل استفاده می کنم. مثلاً اگر دارم type A = [true, true, true]، دریافت خواهم کرد type H = [true, true]. این به این دلیل است که من بررسی می کنم که آیا Aاولین عنصر یک بولی است و من بقیه تاپل را در متغیر نوع دیگری ارسال می کنم.

من از استنتاج نوع در شرط دوم استفاده می کنم تا بررسی کنم که آیا عنصر فعلی در آن وجود دارد یا خیر B. وقتی عنصری در آن وجود دارد A و B، به یاد می آورم Subtract با عناصر باقی مانده از تایپ کنید A (H) و عناصر باقی مانده از B (J). اگر عنصر دیگری در آن وجود نداشته باشد B، ما به تماس ادامه می دهیم Subtract، اما افزایش می دهیم Res در هر تماس و چه زمانی A خالی است، برمی گردیم Res نوع

و اکنون، ما یک تفریق فقط با انواع داریم. توجه داشته باشید که این تفریق فقط با اعداد صحیح مثبت کار می کند. این مشکل ناشی از تاپل است، زیرا بله، شما نمی توانید یک تاپل با طول منفی داشته باشید.

// Example
type TwoFromSubtract = Subtract<Four, Two>;
type TwoFromSubtractResult = Result<TwoFromSubtract>;

// Result
type TwoFromSubtract = [true, true];
type TwoFromSubtractResult = 2;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

راه هوشمند

راه سخت نمونه ناب مهندسی بیش از حد است. زیرا یک روش ساده برای انجام تفریق وجود دارد: تفریق B از A و نتیجه را حفظ کنید.

برای دفاع از خودم، فهمیدم که می توانم از استنتاج نوع بین 2 نوع پویا هنگام کار روی استفاده کنم Divide. اما شما می توانید مرا شرمنده کنید، و اشکالی ندارد.

این هم کد:

type BetterSubtract<A extends TypeNumber, B extends TypeNumber> = A extends [
…B,
…infer Res
] ? Res
: Zero;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

عملیات 3: ضرب

ما قبلاً تمام تکنیک هایی را که برای ضرب کردن نیاز داریم دیده ایم. پس باید اضافه کنیم B بار A شماره این اکنون یک تکه کیک است زیرا تفریق راه سختی است.

برای ضرب، یک حلقه (با انواع بازگشتی) ایجاد کنید. در این حلقه، حذف کنید One از B، اضافه کنید A به نتیجه، و ارسال کنید Res چه زمانی B صفر است. به این ترتیب اضافه می کنیم A B-بار، بنابراین ما انجام می دهیم A x B.

type Multiply<A extends TypeNumber, B extends TypeNumber> = B extends [
boolean,
…infer S
] ? Add<Multiply<A, S>, A>
: [];

// Example
type MultTest = Multiply<Four, Six>;
type MultTestResult = Result<MultTest>;

// Result
type MultTest = [
true,
… 22 more,
true
];
type MultTestResult = 24;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

عملیات 4: تقسیم

ما از ابتدا با اعداد صحیح کار کرده ایم. بنابراین ما فقط می توانیم یک تقسیم اقلیدسی برای این قسمت داشته باشیم.

در تفریق، if را جستجو می کنیم A می تواند شامل شود B و آنچه باقی مانده است ما همین کار را انجام خواهیم داد، با این تفاوت که باید چند بار جستجو کنیم A شامل B. بنابراین ما همان شرط اولیه را با تفریق داریم، اما یک نوع بازگشتی با یک نتیجه افزایشی در هر تکرار حلقه اضافه می کنیم. چه زمانی A نمی تواند شامل شود B دیگر، تعداد حلقه های انجام شده را تا اینجا ارسال کنید.

type Divide<
A extends TypeNumber,
B extends TypeNumber,
Res extends TypeNumber = Zero
> = A extends […B, …infer T] ? Divide<T, B, Add<Res, One>> : Res;

// Example
type DivideTest = Divide<MultTest, Six>;
type DivideTestResult = Result<DivideTest>;
type DivideTest2 = Divide<Six, Four>;
type DivideTest2Result = Result<DivideTest2>;

// Result
type DivideTest = [true, true, true, true];
type DivideTestResult = 4;
type DivideTest2 = [true];
type DivideTest2Result = 1;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پاداش عملیات: ماژول

Modulo تقریباً همان Divide است. ما چند بار بررسی می کنیم A شامل B، و وقتی به پایان رسیدیم، به جای تعداد تکرار، مقدار باقیمانده را برمی گردانیم. و tadaaaaaa، ما عملیات مدول را دریافت می کنیم.

type Modulo<T extends TypeNumber, U extends TypeNumber> = T extends [
…U,
…infer S
] ? Modulo<S, U>
: T;

// Example
type ModuloTest = Modulo<MultTest, Six>;
type ModuloTestResult = Result<ModuloTest>;
type ModuloTest2 = Modulo<Six, Four>;
type ModuloTest2Result = Result<ModuloTest2>;

// Result
type ModuloTest = [];
type ModuloTestResult = 0;
type ModuloTest2 = [true, true];
type ModuloTest2Result = 2;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بنابراین در اینجا ما یک ماشین حساب کار با انواع Typescript داریم. من در مورد پیاده سازی ماشین حساب اعشاری بر اساس نمایش دودویی اعشار فکر کردم. اما این به وضوح دیوانگی است. امیدوارم از خواندن این قطعه برنامه نویسی مانند من از نوشتن آن لذت ببرید. و در آخر، موضوع بحث اولیه ای است که با دوستم در مورد Turing-Complete Typescript داشتم.

با تشکر برای خواندن! از همه ما اینجا، من می خواهم برای شما برنامه نویسی شاد و خدا حفظ کند، دوست من! 🙂

زمان یکی از بی فایده ترین چیزهایی است که تا به حال ساخته ام – چیزی فراتر از عقل، جایی که منطق از عقلانی بودن باز می ایستد و خلأ واقعیت است. زمان آن رسیده است که یک ماشین حساب با استفاده از انواع Typescript ایجاد کنید.


در ابتدا در وبلاگ من، 5 اکتبر 2021 ارسال شد: https://aamulumi.info/Dev/The-Useless-Type-Calculator-in-Typescript


چند روز پیش یاد بحثی با یکی از دوستانم در مورد سیستم های کامل تورینگ افتادم. ما مقاله ویکی‌پدیا را در مورد این موضوع بررسی کردیم و متوجه شدیم که بسیاری از چیزها (مانند بازی‌ها) با تورینگ کامل هستند. بنابراین بله، Minecraft کامل Turing است، Factorio نیز، قلعه کوتوله نیز، و به نظر می رسد که Habbo Hotel و Magic: The Gathering (بله، بازی کارتی) نیز تورینگ کامل هستند.

همچنین در جایی متوجه شدیم که نوع سیستم Typescript Turing-complete است. با این دانش، تصمیم گرفتم شروع به توسعه چیزی کنم که چیزی را تغییر ندهد: یک ماشین حساب فقط با انواع Typescript.

تصویری متحرک از گوردون رمزی در حال دست زدن به صورت.

بله. این یکی از احمقانه ترین ایده هایی است که برای مدتی به ذهنم رسید. اما این یک تمرین سرگرم کننده است که می توانید برای اثبات مهارت های خود در تایپ کردن همه چیز انجام دهید.

قوانین

اگر می خواهید ماشین حساب را انجام دهید، قوانین “بازی” در اینجا آمده است (اگر بتوانیم این را یک بازی بنامیم):

  • شما باید فقط با دو نوع شروع کنید: BZero (برای Boolean Zero) و BOne (برای Boolean One).
type BZero = false;
type BOne = true;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • شما فقط می توانید از انواع استفاده کنید. بدون رابط، بدون enum، فقط انواع.
  • شما باید چهار عملیات اساسی ریاضی (با انواع) را محاسبه کنید: جمع، تفریق، ضرب و تقسیم. شما همچنین می توانید ماژول اضافه کنید.
  • این کد باید کار کند:
// Equivalent of (6 + 6 * (1 + 2)) / (6 - 2) = 6
type StrangeOperation = Divide<
  Add<Multiply<Six, Add<One, Two>>, Six>,
  Subtract<Six, Two>
>;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با توجه به نحوه پیاده سازی ماشین حساب، از نوع دیگری استفاده می کنم Result برای خواندن نتیجه:

type OpResult = Result<StrangeOperation>;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این نوع در قوانین کاملا اختیاری است. اما در پایان محاسبات باید یک نوع عدد دقیق داشته باشید. به عنوان مثال، شما باید داشته باشید:

type OpResult = 6;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و در اینجا شما بروید! وقت آن است که شما کدنویسی کنید!

تصویری متحرک از دختری که دست‌هایش را کف می‌زند و می‌گوید «بریم!»

بله، بهتر است راه حل را بخوانید، اینطور نیست؟

تصویری متحرک از مردی که به روشی هوشمندانه یاب خود را روی سر خود نشان می دهد.

راه حل

مفهوم

در ابتدا، من جستجو می کنم که راه های بدست آوردن یک نوع عدد از یک نوع در Typescript چیست. شما باید عملیات پایه خود را تغییر دهید BZero و BOne به Zero و One شماره اگر این را می دانید

من چیزی را بر اساس شاخص های آرایه امتحان کردم، اما راهی برای بدست آوردن عدد وجود نداشت. بنابراین من متوجه شدم که تاپل های Typescript دارای یک هستند length دارایی و از 3.0 با تاپل های متغیر کار می کند. با این اطلاعات، من شروع به نوشتن یک ماشین حساب بر اساس Tuples کردم.

type TypeNumber = Array<any>;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اولین انواعی که ما نیاز داریم عبارتند از Zero و One بر اساس تاپل ها به این ترتیب، یک نوع شرطی ساده می نویسم که یک تاپل را با تعداد عناصر معادل عددی که توصیف می کند، برمی گرداند. به عنوان مثال:

type ToTypeNumber<A> = A extends true ? [true] : [];

type Zero = ToTypeNumber<BZero>;
type One = ToTypeNumber<BOne>;

// Result
type Zero = [];
type One = [true];
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به این ترتیب به یک تایپ برای خواندن طول تاپل نیاز داریم تا عدد نوع مورد نظر را بدست آوریم.

type Result<A extends TypeNumber> = A["length"];

// Example
type C = Result<One>;

// Result
type C = 1;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

عملیات 1: اضافه کردن

با این تصور، Add type به لطف Typescript 4.0 ساده ترین عملیات برای پیاده سازی است. ما باید دو تاپل را به هم متصل کنیم و یک را انجام دادیم Add نوع

type Add<A extends TypeNumber, B extends TypeNumber> = [...A, ...B];

// Example
type Two = Add<One, One>;
type TwoResult = Result<Two>;
type Four = Add<Two, Two>;
type FourResult = Result<Four>;

// Result
type Two = [true, true];
type TwoResult = 2;
type Four = [true, true, true, true];
type FourResult = 4;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تصویری متحرک از آواز خواندن بیلی الیش

عملیات 2: تفریق

راه سخت

حالا، سرگرمی شروع می شود.

ما باید به محاسبات پشت تفریق فکر کنیم. پس بیایید به مدرسه ابتدایی برگردیم.

من 6 بادکنک دارم. من 4 تا بادکنک به مانو میدم. الان 2 بادکنک باقی مانده است.

از نظر تاپل ها، می توانیم مشکل را با این توضیح دهیم:

type MyBalloons = [true, true, true, true, true, true];
type NewManuBalloons = [true, true, true, true];
type NewMyBalloons = [true, true];
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای اجرای تفریق، هر عنصر را می‌گیرم MyBalloons یکی یکی و بررسی کنید که آیا هر عنصر در آن وجود دارد یا خیر NewManuBalloons. وقتی من در این لحظه می رسم دیگر عنصری در آن وجود ندارد NewManuBallooons، من شروع به افزایش یک متغیر می کنم که نتیجه آن خواهد بود.

اما یک مشکل وجود دارد: به نظر می رسد یک حلقه است. چگونه می توانیم به یک حلقه در Typescript برسیم؟

پاسخ در اینجا استفاده از نوع بازگشتی است. و با یک شرط، می توانیم این کار را با یک نوع شرطی بازگشتی انجام دهیم. این هم کد:

type Subtract<
  A extends TypeNumber,
  B extends TypeNumber,
  Res extends TypeNumber = []
> = A extends [boolean, ...infer H]
  ? B extends [boolean, ...infer J]
    ? Subtract<H, J, Res>
    : Subtract<H, B, Add<Res, One>>
  : Res;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تصویری متحرک از مردی که چشمانش را کاملا باز می کند.

اوه بله، نکته دیگری وجود دارد: من از استنتاج نوع برای حذف عناصر یک تاپل استفاده می کنم. مثلاً اگر دارم type A = [true, true, true]، دریافت خواهم کرد type H = [true, true]. این به این دلیل است که من بررسی می کنم که آیا Aاولین عنصر یک بولی است و من بقیه تاپل را در متغیر نوع دیگری ارسال می کنم.

من از استنتاج نوع در شرط دوم استفاده می کنم تا بررسی کنم که آیا عنصر فعلی در آن وجود دارد یا خیر B. وقتی عنصری در آن وجود دارد A و B، به یاد می آورم Subtract با عناصر باقی مانده از تایپ کنید A (H) و عناصر باقی مانده از B (J). اگر عنصر دیگری در آن وجود نداشته باشد B، ما به تماس ادامه می دهیم Subtract، اما افزایش می دهیم Res در هر تماس و چه زمانی A خالی است، برمی گردیم Res نوع

و اکنون، ما یک تفریق فقط با انواع داریم. توجه داشته باشید که این تفریق فقط با اعداد صحیح مثبت کار می کند. این مشکل ناشی از تاپل است، زیرا بله، شما نمی توانید یک تاپل با طول منفی داشته باشید.

// Example
type TwoFromSubtract = Subtract<Four, Two>;
type TwoFromSubtractResult = Result<TwoFromSubtract>;

// Result
type TwoFromSubtract = [true, true];
type TwoFromSubtractResult = 2;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

راه هوشمند

راه سخت نمونه ناب مهندسی بیش از حد است. زیرا یک روش ساده برای انجام تفریق وجود دارد: تفریق B از A و نتیجه را حفظ کنید.

برای دفاع از خودم، فهمیدم که می توانم از استنتاج نوع بین 2 نوع پویا هنگام کار روی استفاده کنم Divide. اما شما می توانید مرا شرمنده کنید، و اشکالی ندارد.

این هم کد:

type BetterSubtract<A extends TypeNumber, B extends TypeNumber> = A extends [
  ...B,
  ...infer Res
]
  ? Res
  : Zero;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تصویر متحرک مردی که با انگشت سرش را نشان می دهد (به روشی هوشمندانه).

عملیات 3: ضرب

ما قبلاً تمام تکنیک هایی را که برای ضرب کردن نیاز داریم دیده ایم. پس باید اضافه کنیم B بار A شماره این اکنون یک تکه کیک است زیرا تفریق راه سختی است.

برای ضرب، یک حلقه (با انواع بازگشتی) ایجاد کنید. در این حلقه، حذف کنید One از B، اضافه کنید A به نتیجه، و ارسال کنید Res چه زمانی B صفر است. به این ترتیب اضافه می کنیم A B-بار، بنابراین ما انجام می دهیم A x B.

type Multiply<A extends TypeNumber, B extends TypeNumber> = B extends [
  boolean,
  ...infer S
]
  ? Add<Multiply<A, S>, A>
  : [];

// Example
type MultTest = Multiply<Four, Six>;
type MultTestResult = Result<MultTest>;

// Result
type MultTest = [
  true,
  ... 22 more,
  true
];
type MultTestResult = 24;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تصویری متحرک از زنی که سرش را مانند «اوه خیلی خوب» خم کرده است

عملیات 4: تقسیم

ما از ابتدا با اعداد صحیح کار کرده ایم. بنابراین ما فقط می توانیم یک تقسیم اقلیدسی برای این قسمت داشته باشیم.

در تفریق، if را جستجو می کنیم A می تواند شامل شود B و آنچه باقی مانده است ما همین کار را انجام خواهیم داد، با این تفاوت که باید چند بار جستجو کنیم A شامل B. بنابراین ما همان شرط اولیه را با تفریق داریم، اما یک نوع بازگشتی با یک نتیجه افزایشی در هر تکرار حلقه اضافه می کنیم. چه زمانی A نمی تواند شامل شود B دیگر، تعداد حلقه های انجام شده را تا اینجا ارسال کنید.

type Divide<
  A extends TypeNumber,
  B extends TypeNumber,
  Res extends TypeNumber = Zero
> = A extends [...B, ...infer T] ? Divide<T, B, Add<Res, One>> : Res;

// Example
type DivideTest = Divide<MultTest, Six>;
type DivideTestResult = Result<DivideTest>;
type DivideTest2 = Divide<Six, Four>;
type DivideTest2Result = Result<DivideTest2>;

// Result
type DivideTest = [true, true, true, true];
type DivideTestResult = 4;
type DivideTest2 = [true];
type DivideTest2Result = 1;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تصویری متحرک از دو مرد که می‌گویند «آسان بود»

پاداش عملیات: ماژول

Modulo تقریباً همان Divide است. ما چند بار بررسی می کنیم A شامل B، و وقتی به پایان رسیدیم، به جای تعداد تکرار، مقدار باقیمانده را برمی گردانیم. و tadaaaaaa، ما عملیات مدول را دریافت می کنیم.

type Modulo<T extends TypeNumber, U extends TypeNumber> = T extends [
  ...U,
  ...infer S
]
  ? Modulo<S, U>
  : T;

// Example
type ModuloTest = Modulo<MultTest, Six>;
type ModuloTestResult = Result<ModuloTest>;
type ModuloTest2 = Modulo<Six, Four>;
type ModuloTest2Result = Result<ModuloTest2>;

// Result
type ModuloTest = [];
type ModuloTestResult = 0;
type ModuloTest2 = [true, true];
type ModuloTest2Result = 2;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


بنابراین در اینجا ما یک ماشین حساب کار با انواع Typescript داریم. من در مورد پیاده سازی ماشین حساب اعشاری بر اساس نمایش دودویی اعشار فکر کردم. اما این به وضوح دیوانگی است. امیدوارم از خواندن این قطعه برنامه نویسی مانند من از نوشتن آن لذت ببرید. و در آخر، موضوع بحث اولیه ای است که با دوستم در مورد Turing-Complete Typescript داشتم.

با تشکر برای خواندن! از همه ما اینجا، من می خواهم برای شما برنامه نویسی شاد و خدا حفظ کند، دوست من! 🙂

تصویری متحرک از ژان کلود ون دام که در حال انجام شکاف بزرگ (امیدوارم این کلمه باشد) و گفتن

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا