<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Poom Yimyuean on Medium]]></title>
        <description><![CDATA[Stories by Poom Yimyuean on Medium]]></description>
        <link>https://medium.com/@lebrancconvas?source=rss-84e1e2001f4d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*dxPlZdXF7UFiI2CSQrolFw.jpeg</url>
            <title>Stories by Poom Yimyuean on Medium</title>
            <link>https://medium.com/@lebrancconvas?source=rss-84e1e2001f4d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 01:04:03 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@lebrancconvas/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[ทำความเข้าใจเบื้องหลังของ Utility Type ในภาษา TypeScript — Chapter 01: Partial]]></title>
            <link>https://lebrancconvas.medium.com/%E0%B8%97%E0%B8%B3%E0%B8%84%E0%B8%A7%E0%B8%B2%E0%B8%A1%E0%B9%80%E0%B8%82%E0%B9%89%E0%B8%B2%E0%B9%83%E0%B8%88%E0%B9%80%E0%B8%9A%E0%B8%B7%E0%B9%89%E0%B8%AD%E0%B8%87%E0%B8%AB%E0%B8%A5%E0%B8%B1%E0%B8%87%E0%B8%82%E0%B8%AD%E0%B8%87-utility-type-%E0%B9%83%E0%B8%99%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2-typescript-chapter-01-partial-f0d3ac8b7b10?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/f0d3ac8b7b10</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[type]]></category>
            <category><![CDATA[utility-types]]></category>
            <category><![CDATA[type-challenge]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Wed, 02 Oct 2024 00:51:17 GMT</pubDate>
            <atom:updated>2024-10-02T00:56:29.488Z</atom:updated>
            <content:encoded><![CDATA[<h3>ทำความเข้าใจเบื้องหลังของ Utility Type ในภาษา TypeScript — Partial</h3><h3>เกริ่น</h3><p>ช่วงนี้เรากลับมาทำ Type Challenge อีกครั้ง แล้วรู้สึกว่าการทำความเข้าใจเบื้องหลังการสร้าง Utility Type เป็นหนึ่งในวิธีที่ทำให้เริ่มเข้าใจ และ เข้าสู่โลกของ Advanced Type ใน TypeScript ที่ดีเลยล่ะฮะ</p><h3>Partial&lt;Type&gt;</h3><p>Partial เป็น Utility Type ที่รับ Type Parameter เข้ามาหนึ่งตัวในลักษณะของ Object ในรูปแบบ {key01: type01, key02: type02} อะไรประมาณนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v7YssbKcgqlMMh7GMH5KJw.png" /><figcaption>ผลลัพธ์เมื่อเราไป hover ตรง Type ที่ผ่านการสร้างโดยใช้ Partial มา แล้วนี้คือสิ่งที่ Language Server ทำการ suggest มาให้เรา</figcaption></figure><p>ผลลัพธ์ที่ได้คือ เราจะได้ Type ที่เป็น Object ตัวนั้น แต่ Key ทุกอันของ Object นั้นๆ จะมีลักษณะเป็น Optional (คือจะใส่ค่าเป็นตาม Type ที่กำหนดใน key หรือ ปล่อยว่างให้มันเป็น undefined ก็ได้)</p><h4>เบื้องหลังของ Partial&lt;Type&gt;</h4><p>ซึ่งเบื้องหลังของโค้ด Partial (ซึ่งเราขอยกตัวอย่างเป็น Partial ที่เรา Custom มาเอง ให้มีลักษณะเหมือนกับ Partial จริงๆ) มันจะเป็นอย่างงี้ครับ</p><pre>type CustomPartial&lt;T&gt; = {<br>    [P in keyof T]?: T[P];<br>};</pre><p>จากโค้ดเราจะเห็นได้ว่าเราจะกำหนด Type ที่เป็น Generic Type ที่รับ Type Parameter เป็นตัวแปร T ในลักษณะของ Object เข้ามาหนึ่งตัว</p><p>โดยที่เรากำหนดตัวแปรอีกตัวเป็น P เอาไว้แทนค่าของ keyof T (หรือก็คือ P เป็นตัวแปรตัวแทนของ Key ทั้งหมดของ T)</p><p>โดยที่ถ้าเราสังเกตดีๆจะมีเครื่องหมาย “?” ตามหลัง [p in keyof T] เป็นการสื่อว่า ให้ทั้งก้อนในวงเล็บที่สื่อว่า P เป็นตัวแปรแทน Key ทั้งหมดของ T (Object Type) โดยให้ key ทั้งหมดเนี่ยมีลักษณะเป็น Optional หมายความว่า Key ทุกตัวใน Object นั้น ไม่จำเป็นต้องใส่ให้ object ที่ถูก annotate ด้วย Partial Type ตัวนี้</p><p>(เครื่องหมาย ? เป็นสัญลักษณ์ในภาษา TypeScript ที่เรามักจะเอาไว้ใช้หลัง key ใน object เพื่อเป็น mark ว่า key นั้นมีลักษณะเป็น Optional หรือบางทีก็ใช้หลัง Parameter ตอนที่สร้างฟังก์ชัน เพื่อบอกว่าเราไม่จำเป็นต้องใส่ Argument เข้าไปแทน Parameter ตัวนี้ทุกครั้งที่สร้างฟังก์ชันเช่นกันฮะ)</p><h3>อ้างอิง (Reference)</h3><ul><li><a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype">TypeScript: Documentation — Utility Types (typescriptlang.org)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f0d3ac8b7b10" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ลองสร้าง 16-Bits Virtual Machine อย่างง่ายด้วยภาษา JavaScript / TypeScript —  Chapter 00: เกริ่นนำ]]></title>
            <link>https://lebrancconvas.medium.com/%E0%B8%A5%E0%B8%AD%E0%B8%87%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-16-bits-virtual-machine-%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B8%87%E0%B9%88%E0%B8%B2%E0%B8%A2%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2-javascript-typescript-chapter-00-%E0%B9%80%E0%B8%81%E0%B8%A3%E0%B8%B4%E0%B9%88%E0%B8%99%E0%B8%99%E0%B8%B3-c73633e53e94?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/c73633e53e94</guid>
            <category><![CDATA[computer-architecture]]></category>
            <category><![CDATA[virtual-machine]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[hardware]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Sat, 21 Sep 2024 13:10:41 GMT</pubDate>
            <atom:updated>2024-09-22T09:42:25.496Z</atom:updated>
            <content:encoded><![CDATA[<h3>ลองสร้าง 16-Bits Virtual Machine อย่างง่ายด้วยภาษา JavaScript / TypeScript — Chapter 00: เกริ่นนำ</h3><h3>เกริ่น</h3><p>ช่วงนี้มีโอกาสระหว่างที่กำลังหางานด้วย ก็กำลังสนใจเรื่องเกี่ยวกับ Game Console / Emulator Development อยู่พอดี เนื่องมาจากเราเป็นเด็กที่โตมากับการเล่นเกมใน Console ผ่าน Emulator + ROM ในขวบวัยที่ยังไม่ประสีประสาเรื่องลิขสิทธิ์ แค่อยากเล่นเกม แต่ไม่มีตังค์ซื้อเครื่อง พอโตมาเลยสนใจว่าเราสามารถจำลองเครื่องเกมเพื่อเปิดเล่นใน PC ได้ยังไง ซึ่งก็นับว่าเป็นโอกาสที่ดีที่จะได้ทบทวนความรู้เรื่อง Computer Architecture กับ Assembly</p><p>แล้วก็ดันเป็นจังหวะที่ดีมากๆที่ได้ไปเจอกับโปรเจคนี้</p><p><a href="https://github.com/francisrstokes/tega">francisrstokes/tega: 🕹 TypeScript Embedded GameBoy Macro Assembler (github.com)</a></p><p>ตัวนี้เป็นโปรเจค tega ของคุณ <a href="https://github.com/francisrstokes">Francis Stokes (francisrstokes)</a> ซึ่งเป็น Library สำหรับการ Assembler ตัว <a href="https://en.wikipedia.org/wiki/ROM_image">ROM Image</a> เพื่อเอาไปรันบนเครื่องเกม <a href="https://en.wikipedia.org/wiki/Game_Boy">GameBoy (GB)</a> หรือ รันบน <a href="https://github.com/DerekTurtleRoe/awesome-emulators?tab=readme-ov-file#nintendo-game-boygame-boy-color">Emulator ของ GameBoy (GB)</a></p><p>ส่วนตัวที่น่าสนใจคือเป็น TypeScript ด้วยนี่แหละ คิดว่าน่าสนใจที่จะลองเอาภาษาที่ตัวเองถนัด แล้วใช้ขึ้นงานได้คล่องดี มาลอง Implement ก่อนเพื่อศึกษาคอนเซปต์ยากๆบางอย่างที่เราสนใจ ก่อนที่จะเอาความเข้าใจในคอนเซปต์นั้นๆไปพัฒนาต่อในภาษาอื่นที่น่าสนใจเหมือนกัน หรือ อาจจะดูเหมาะสมกว่า หรือ รีดเค้นความสามารถ หรือ ประสิทธิภาพที่ดีกว่า เช่น Go, Rust, C++, Zig (ตัวนี้ผมยังไม่เคยลองเขียนเลย), Haskell, Clojure ลองแม่งให้หมดอะ เอาดิ (จริงๆเราว่าการลองทำโปรเจคใหญ่ๆโปรเจคนึงในหลายๆภาษาเป็นเรื่องดีนะ จะได้รู้จุดแข็ง รู้ข้อจำกัดของภาษา เรียนรู้ Mental Model ของภาษาต่างๆ และหาวิธีการเค้นความสามารถของแต่ละภาษาเพื่อมาพัฒนาโปรเจคนึงของเราให้ออกมาในรูปแบบต่างๆที่ต้องการ แต่ก็ยังไม่มีความขยันพอจะทำขนาดนั้นเหมือนกัน แหะๆ = =” )</p><p>ซึ่งก็โชคดีมากๆที่คุณ Francis เขามี<a href="https://www.youtube.com/@LowByteProductions">ช่อง Youtube ของตัวเองที่ใช้ชื่อว่า “Low Level Productions”</a> ซึ่งมักจะสอนคอนเซปต์ Low Level ต่างๆโดยหลายๆโปรเจคที่เขาหยิบมาทำ มาสอนจะ implement โดยใช้ภาษา JavaScript / TypeScript</p><p><a href="https://www.youtube.com/@LowByteProductions">Low Byte Productions</a></p><p>ซึ่งหนึ่งในโปรเจคในช่องของเขาที่เราว่าน่าสนใจจะเอามาลองฝึกหัดทำ และ เอามาเล่าในนี้ก็คือ<a href="https://github.com/lowbyteproductions/16-Bit-Virtual-Machine">โปรเจค 16-Bit Virtual Machine</a></p><p><a href="https://github.com/lowbyteproductions/16-Bit-Virtual-Machine">lowbyteproductions/16-Bit-Virtual-Machine: Code for the “16-Bit Virtual Machine” Series (github.com)</a></p><p><a href="https://www.youtube.com/playlist?list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b">16-Bit Virtual Machine — YouTube</a></p><h3>อธิบายโปรเจค</h3><p>โจทย์ของโปรเจคนี้มีอยู่ว่าเราต้องการ 16-Bits Virtual Machine</p><p>แล้วอะไรคือ 16-Bits Virtual Machine ?</p><h4>16-Bits Virtual Machine</h4><ul><li>Virtual Machine: ตรงนี้ให้เราเข้าใจกันคร่าวๆว่าหมายถึง การจำลองระบบคอมพิวเตอร์ โดยอ้างอิงจากสถาปัตยกรรมของคอมพิวเตอร์ที่เราใช้งานกัน เพราะเอาเข้าจริง Virtual Machine ก็มีหลายแบบ หากเราบอกว่าเป็นการอ้างอิงจากสถาปัตยกรรมของคอมพิวเตอร์ สถาปัตยกรรมของคอมพิวเตอร์ก็มีหลายแบบอีก ไม่ได้มีแค่แบบเดียว</li></ul><p>แต่คำถามที่สำคัญกว่าคือ อะไรคือ 16-Bits ในบริบทของ Virtual Machine ที่เราจะสร้างกัน</p><p>ซึ่งจริงๆก็ไม่ได้ซับซ้อนอะไรเลย ความหมายของ 16 Bits ในที่นี้หมายความว่า การเก็บค่า Instruction Set, ค่าของ Register, ค่าของ Memory และ ค่าต่างๆภายใน Virtual Machine ตัวที่เราจะสร้างกันเนี่ย จะใช้พื้นที่ในการเก็บข้อมูลพวกนี้สำหรับแต่ละตัวอยู่ที่ขนาดสูงสุด 16 Bits หรือก็คือ 16 / 4 = 4 Bytes นั่นเอง</p><h4>เป้าหมายของโปรเจค (Goal)</h4><p>เป้าหมายของโปรเจคนี้ คือ เราต้องการพัฒนาตัว 16-Bits Virtual Machine ของเราให้มี <a href="https://en.wikipedia.org/wiki/Functional_requirement">Functional Requirement</a> ประมาณนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H625lu8-rJ_ACBH-lNh1iA.jpeg" /><figcaption>ขอบคุณรูปภาพจาก<a href="https://youtu.be/fTBwD3sb5mw?si=dUHc5GO1hGZE19K6">วิดีโอ 16-Bit Virtual Machine in JavaScript 001 จากช่อง Low Byte Productions</a></figcaption></figure><ul><li><strong>A Flexible, Extensible, Register-Based Virtual Machine:</strong> Virtual Machine ที่มีความยืดหยุ่น และ ขยายขนาดได้ และเป็น Virtual Machine ประเภทที่เก็บข้อมูลที่ใช้สำหรับการดำเนินการต่างๆลงใน Register เป็นหลัก</li><li><strong>Signed, Unsigned, and Floating-Point Operations:</strong> สามารถดำเนินการทางคณิตศาสตร์กับตัวเลขที่เป็นจำนวนเต็มแบบ Signed (นับรวมจำนวนเต็มลบ), Unsigned (นับเฉพาะจำนวนเต็มบวก), Floating-Point (จำนวนทศนิยม)</li><li><strong>Call Stack / Stack Frame Structure:</strong> มีส่วนของ Stack ใน Memory เพื่อเก็บค่าไว้สำหรับการดำเนินการใน <a href="https://en.wikipedia.org/wiki/Function_(computer_programming)">Subroutine (Function)</a> ต่างๆ</li><li><strong>Interrupt Capabilities:</strong> มีความสามารถในการหยุด หรือ ขัดจังหวะการทำงานภายในตัว Virtual Machine ได้</li><li><strong>Memory Mapping:</strong> มี Memory Mapper ที่มีความสามารถในการทำ Memory Mapping ค่าข้อมูลของตัวส่วนต่างๆเข้ากับ Memory เช่น I/O Device <a href="https://en.wikipedia.org/wiki/Memory-mapped_I/O_and_port-mapped_I/O">(Memory-Mapped I/O: MMIO)</a></li><li><strong>Powerful Assembly Language:</strong> มีการทำภาษา Assembly ภายในตัว Virtual Machine เพื่อเอาไว้ใช้เขียนคำสั่งจัดการกับค่าๆต่างๆในตัว Virtual Machine</li><li><strong>C-Like Language:</strong> สร้างภาษาที่คล้ายกับภาษา C เพื่อเอามาจำลองการเขียนซอฟต์แวร์เพื่อเอาไว้รันในตัว Virtual Machine</li><li><strong>Fantasy Game Console:</strong> จำลองการทำงานของเครื่องเกม (Game Console) ภายในตัว Virtual Machine ได้</li></ul><p>ซึ่งรายละเอียดต่างๆ หรือพวกศัพท์ที่อาจจะดูไม่คุ้นเคยในลิสต์นี้ เดี๋ยวเราจะค่อยๆอธิบายในแต่ละตอนนะว่ามันหมายถึงอะไร มันทำงานอะไร ยังไง</p><h3>ปิดท้าย</h3><p>ก็จบกันไปแล้วสำหรับ Chapter แรกของซีรีส์บทความการสร้าง 16-Bits Virtual Machine ด้วยภาษา JavaScript / TypeScript สำหรับ Chapter ก็ไม่มีอะไรมาก แค่มาเกริ่น กับ อธิบายเบื้องต้นว่าในซีรีส์บทความนี้เราจะทำอะไรกัน ส่วนรายละเอียดต่างๆ เราจะเริ่มค่อยๆอธิบายในตอนถัดๆไป ยังไงก็ขอบคุณผู้อ่านที่อ่านมาจนถึงตอนนี้ มีข้อชี้แนะ หรือ สงสัยอย่างไร หรือ อยากจะพูดคุยอะไร สามารถคอมเมนต์มาได้เลยนะครับ สำหรับบทความนี้ก็ขอตัวก่อนนะครับ ขอบคุณครับ</p><h3>แหล่งอ้างอิง (Reference)</h3><ul><li><a href="https://medium.com/@pcm4150/stack-based-vm-vs-register-based-vm-8769f96ba2e5">Stack based VM vs. Register based VM | by Chang Min Park | Medium</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c73633e53e94" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[Note] ว่าด้วยเรื่อง Bit ในภาษา JavaScript / TypeScript ตามความเข้าใจ]]></title>
            <link>https://lebrancconvas.medium.com/note-%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2%E0%B9%80%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87-bit-%E0%B9%83%E0%B8%99%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2-javascript-typescript-%E0%B8%95%E0%B8%B2%E0%B8%A1%E0%B8%84%E0%B8%A7%E0%B8%B2%E0%B8%A1%E0%B9%80%E0%B8%82%E0%B9%89%E0%B8%B2%E0%B9%83%E0%B8%88-6cfa1d39cd27?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/6cfa1d39cd27</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[binary-number]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[bitwise-operator]]></category>
            <category><![CDATA[bitwise]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Mon, 16 Sep 2024 07:13:46 GMT</pubDate>
            <atom:updated>2024-10-02T00:10:08.216Z</atom:updated>
            <content:encoded><![CDATA[<h3>[Note] ว่าด้วยเรื่อง Bitๆ Byteๆ ในภาษา JavaScript / TypeScript ตามความเข้าใจ</h3><h3>Disclaimer</h3><p>บทความที่มีการจั่วหัว Headline ว่า “[Note]” หมายถึงเป็นบทความที่มีลักษณะเหมือนเป็นโน้ตการเรียนรู้ส่วนตัวของเรา ที่เปิดเป็นสาธารณะให้คนเข้ามาอ่าน มาแสดงความคิดเห็นได้ มันเลยอาจจะอยู่ในลักษณะเป็นเหมือน bullet (เป็นสไตล์การโน้ตของเรา) ที่เราอาจจะเข้ามาเติมเนื้อหาข้างในนี้ได้เรื่อยๆ ไม่ได้จบ สมบูรณ์ในตัวเป็น Blog อะไรขนาดนั้น ด้วยความที่ตัว medium หรือหลายๆ platform ก็เปิดโอกาสให้เราเข้ามา edit บทความที่ publish ลงไปแล้วเป็น version ใหม่ๆได้เรื่อยๆ เป็นแนวแบบโน้ตไปได้นิดนึงก็ publish มีอะไรอยากเพิ่มก็ค่อยมาแก้ มีความเห็นเพิ่มเติม หรือ ต้องแก้ไข ก็ค่อยมาแก้</p><h3>Binary Number, Bit, Byte</h3><p>เลขฐานสอง (Binary Number) ประกอบไปด้วยสมาชิกคือจำนวน 0 กับ 1 โดยทั่วไปแล้วจำนวนหลักของเลขฐานสอง จะถูกเข้าใจตรงกันว่าหมายถึง บิต (Bit) โดยเรียงหลักที่มีค่าน้อยจากขวาไปซ้าย ใช้วิธีคิดแบบเดียวกับเลขฐานสิบ (Decimal Number) และเลขฐานอื่นๆ</p><ul><li>8 Bits หรือ 8 หลักของเลขฐานสอง จะมีค่าเท่ากับ 1 Byte</li><li>เวลาแปลง Byte เป็น Bit ก็แค่เอา Byte * 8 เช่น 2 Bytes = 2*8 = 16 Bits</li><li>เวลาแปลง Bit เป็น Byte ก็แค่เอา Bit / 8 เช่น 24 Bits = 24 / 8 = 3 Bytes</li><li>เลขฐานสิบหกที่มีสมาชิกตั้งแต่ 0 — F จะใช้จำนวน Bit อย่างน้อยที่สุดในการแทนจากเลขฐานสิบหก เป็น เลขฐานสองทั้งหมด 4 Bits ดังนี้ (หมายเหตุ: “0x” เป็นตัวบ่งชี้ว่าเลขหลังจากนั้นเป็นเลขฐานสิบหกเฉยๆ / “0b” ก็เป็นตัวบ่งชี้ว่าเลขหลังจากนั้นเป็นเลขฐานสองเฉยๆ)</li></ul><p>0x0 = 0b0000</p><p>0x1 = 0b0001</p><p>0x2 = 0b0010</p><p>0x3 = 0b0011</p><p>0x4 = 0b0100</p><p>0x5 = 0b0101</p><p>0x6 = 0b0110</p><p>0x7 = 0b0111</p><p>0x8 = 0b1000</p><p>0x9 = 0b1001</p><p>0xA = 0b1010</p><p>0xB = 0b1011</p><p>0xC = 0b1100</p><p>0xD = 0b1101</p><p>0xE = 0b1110</p><p>0xF = 0b1111</p><h3>ArrayBuffer, TypedArray</h3><ul><li>หมายความว่า เราสามารถแทน 1 Byte ด้วยตัวเลขฐานสิบหกทั้งหมด 8/4 = 2 หลักของเลขฐานสิบหก เราเลยเห็นการแทนค่า 1 Byte อยู่ในรูปของ 00 หรือกลุ่มของสองหลักของเลขฐานสิบหก ใน <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer">ArrayBuffer</a> มีกลุ่มของเลขฐานสิบหกสองหลักอยู่กี่ตัว ก็เท่ากับขนาด Byte ของ ArrayBuffer ตัวนั้นๆ</li><li>Number Type ใน JavaScript / TypeScript เต็มที่อยู่ที่ขนาด 32 Bits หมายความว่าถ้าเราจะสร้าง ArrayBuffer จะสามารถสร้าง ArrayBuffer ได้อยู่ที่ขนาดสูงสุด = 2³² Bits หรือประมาณ 4 Gigabytes (4 GBs)</li><li>ลืมบอกไปว่า ArrayBuffer หรือเรียกอีกชื่อนึงว่า “Byte Array” ใน JavaScript / TypeScript หมายถึง Object ที่เก็บค่า Binary เอาไว้ในรูปแบบของ Byte ซึ่งเราไม่สามารถจัดการกับ ArrayBuffer โดยตรงได้ จะต้องเอามาจัดการผ่านสิ่งที่เรียกว่า <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView">DataView</a></li><li>เราสามารถสร้าง ArrayBuffer ใน JavaScript / TypeScript ดังนี้</li></ul><pre>const SIZE = 128; // กำหนดขนาดของ ArrayBuffer ตามที่ต้องการ ซึ่งค่านี้จะอยู่ในหน่วย Byte(s) <br>const arrayBuffer = new ArrayBuffer(SIZE);<br>const dataView = new DataView(arrayBuffer);</pre><ul><li>จากโค้ดข้างต้น อธิบายคือเรากำหนด Size หรือจำนวน Byte หรือ พื้นที่ที่มีหน่วยเป็น Byte ที่จะใช้ก่อน จากนั้นเราก็ค่อยสร้าง Object ของ ArrayBuffer โดยรับค่า Size เข้าไป เนื่องจากอย่างที่บอกไปแล้วว่าเราต้องจัดการกับข้อมูลของ Buffer ผ่าน DataView เราจึงต้องสร้าง Object ของ DataView ที่รับค่า ArrayBuffer เข้าไป</li><li>Method ส่วนใหญ่ใน DataView ที่ทำให้เราสามารถจัดการกับค่าใน ArrayBuffer ได้ จะเป็น Set, Get Method โดยจะเป็น Set, Get ค่าโดยอิงตาม <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray">TypedArray</a> แบบต่างๆ (setUint8, getUint8, setUint16, getUint16, etc.)</li><li>ไปเจอตัวอย่างหนึ่งใน MDN Web Docs มา น่าสนใจที่จะเอามายกในนี้</li></ul><pre>const { buffer } = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);<br>const data = new DataView(buffer);<br>console.log(data.getUint16(1)); // Answer: 258 </pre><ul><li>อ่านโค้ดข้างต้นแล้วสงสัยไหมว่า “ทำไมค่าที่ log ออกมาถึงได้ 258 ?” (ลอง Copy &amp; Paste ตัวโค้ดแล้วเอาไปรันกันได้นะ)</li><li>ก่อนอื่นต้องบอกก่อนว่าโค้ดข้างต้นก็เป็นอีกวิธีที่เราสามารถใช้สร้าง ArrayBuffer ได้นะ คือเราดึงเอา buffer จากการสร้าง instance ของ TypedArray (อย่างในโค้ดคือ TypedArray ประเภท <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array">Uint8Array</a>) ออกมาเป็น ArrayBuffer ได้เลย Type ของมันจะเป็น <a href="https://stackoverflow.com/questions/52416170/the-deep-meaning-of-arraybufferlikes-typescript-definition">ArrayBufferLike</a> (เปรียบดั่ง ArrayBuffer) ซึ่งสามารถเอาไปใส่เป็น argument ตอนสร้าง DataView ได้เช่นกัน</li><li>ทีนี้เวลาเราสร้าง ArrayBuffer มาเนี่ย ค่าที่ Input มาใน Array ตอนแรกที่เป็นเลขฐานสิบ เวลามาแปลงเป็น Byte ใน ArrayBuffer จะอยู่ในรูปของเลขฐานสิบหก สองหลัก ตามที่ได้กล่าวไปก่อนแล้ว</li><li>Uint8Array เดิมอยู่ในรูป [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] พอมาอยู่ในรูป ArrayBuffer จึงออกมาเป็น &lt;00 01 02 03 04 05 06 07 08 09&gt; (ด้วยความที่มันเป็น Uint8Array หรือก็คือ 8-Bits Unsigned Integer พอเอามาใส่ใน ArrayBuffer เลยใช้พื้นที่แค่ 8/8 = 1 Byte ในการบรรจุค่า Element แต่ละตัวใน Uint8Array เดิม ลงใน ArrayBuffer)</li><li>ในโค้ดเราใช้ Method getUint16(1) หมายความว่า Method ให้เราดึงค่า 16-Bits Unsigned Integer ออกมาโดยเริ่มต้นดึงจาก ArrayBuffer ในตำแหน่ง (byteOffSet) ที่ 1 (byteOffSet อารมณ์มันเหมือนตำแหน่งของ Byte ใน ArrayBuffer อาจจะเข้าใจว่าคล้ายๆกับ Index ใน Array แบบที่เราใช้กันปกติก็คงพอได้อยู่)</li><li>ซึ่งถ้าเราลองดูใน ArrayBuffer ดีๆ ตำแหน่งที่ 1 จะเป็นเลข 01 แต่ด้วยความที่เราใช้การดึงแบบ 16-Bits Unsigned Integer, 16 Bits หมายความว่าต้องดึงออกมา 16/8 = 2 Bytes โดยเริ่มจากตำแหน่งที่ 1 ของ ArrayBuffer ตามที่บอกไปแล้ว หมายความว่าค่าที่เราดึงออกมาจาก ArrayBuffer ผ่าน getUint16(1) ก็คือค่า 01 02 เอามารวมเป็นเลขเดียวกันก็คือ 0x0102</li><li>พอเราเอา 0x0102 ซึ่งเป็นเลขฐานสิบหก มาแปลงเป็นเลขฐานสิบ ก็จะได้เท่ากับ ((1 * 16²) + (2 * 16⁰)) = 256 + 2 = 258 (1 อยู่ในหลักที่ 2, ส่วน 2 อยู่ในหลักที่ 0) ซึ่งก็คือค่าที่ log ออกมาตามในโค้ดที่ยกตัวอย่างนั่นเอง !</li><li>มีอีกตัวอย่างหนึ่งที่น่าสนใจ ลองเอามาให้ดูกัน</li></ul><pre>const { buffer } = new Uint16Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);<br>console.log(buffer); </pre><ul><li>จากโค้ดคิดว่า ArrayBuffer ที่ออกมาจะมีหน้าตาเป็นอย่างไร ?</li><li>ตอนแรกผมเข้าใจว่าพอเป็น Uint16 (16-Bits Unsigned Integer) การเก็บตัวเลข 1 ตัวใน ArrayBuffer จะต้องใช้ 16/8 = 2 Bytes ผมเลยคิดว่ามันน่าจะเรียงออกมาแบบนี้ -&gt; &lt;00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09&gt;</li><li>ซึ่งผลลัพธ์จริงๆมันออกมาเป็นแบบนี้ -&gt; &lt;00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00&gt;</li><li>มันใช้พื้นที่ในการเก็บตัวเลขจาก Array เดิม 2 Bytes ก็จริง แต่การเรียงตัวเลขกลับดูแปลกๆไปจากที่คิดไว้นิดนึง คือ มันเรียงแบบเอาสองหลักหลังของตัวเลขแต่ละตัวมาสลับไว้ข้างหน้า ซึ่งตอนแรกผมก็ไม่เข้าใจว่าทำไม</li></ul><h4><a href="https://en.wikipedia.org/wiki/Endianness">Endianness</a></h4><ul><li>จนพอลองหาๆไปก็พบว่ามันมีคอนเซปต์หนึ่งที่เรียกว่า <a href="https://developer.mozilla.org/en-US/docs/Glossary/Endianness">Endianness</a> (หรือ “Byte-Order”)</li><li>Endianness จะมีอยู่สองลักษณะที่ใช้กันหลักๆ ได้แก่ Big-Endian กับ Little-Endian (จริงๆจะมี Mix-Endian อีกอัน แต่ไม่ค่อยได้ใช้แล้ว)</li><li>กำหนดเลข 0x0102 ขึ้นมา</li><li>ถ้าเป็นการเรียงในลักษณะ Big-Endian จะเป็นการเรียง Byte ตามที่เรากำหนดมาเลย คือ &lt;01 02&gt;</li><li>แต่ถ้าเป็นการเรียงในลักษณะ Little-Endian จะเป็นการเรียง Byte ในลักษณะที่เอา Byte จากตำแหน่งหลัง มาไว้ใน index ของ ArrayBuffer หน้าสุดก่อน ก็จะได้ผลลัพธ์ในการจัดเรียงเป็น ArrayBuffer ว่า &lt;02 01&gt;</li><li>ซึ่งการเรียงแบบ Big-Endian เป็นการเรียงแบบที่ผมเข้าใจแต่แรกว่ามันน่าจะเป็นแบบนั้น</li><li>แต่เข้าใจว่าโดย Default ของการแปลงเลขจาก TypedArray มาเป็น ArrayBuffer น่าจะใช้การเรียงแบบ Little-Endian</li></ul><h3>Bitwise Operation</h3><ul><li>Bit มีการดำเนินการที่เราเรียกว่า Bitwise Operation ซึ่งเป็นการดำเนินการแบบเดียวกับเวลาเราเรียนวิชาตรรกศาสตร์ หรือ เรียนเรื่อง Logic Gate ในสาขา Electronics หรือ Computer การดำเนินการที่เราใช้หลักๆ คือ ~ (NOT), &amp; (AND), | (OR), ^ (XOR) (เราสามารถใช้ความเข้าใจในตรรกศาสตร์ กับ Logic Gate มาทำความเข้าใจร่วมกันได้ เนื้อหาค่อนข้างที่จะใช้ร่วมกันได้ ต่างกันแค่ Use Case ในการนำไปประยุกต์ใช้)</li><li>~ (NOT): คือ การแปลง Bit ปัจจุบัน ให้เป็นอีกตัวนึง (0 แปลงเป็น 1, 1 แปลงเป็น 0) ถ้าเราเขียนเลขในรูปแบบหลาย Bit การใช้ ~ จะหมายถึงแปลงค่าทุก Bit ให้เป็นเลขอีกตัว เช่น ~(0b0110) = 0b1001</li><li>&amp; (AND): คือ <a href="https://th.wikipedia.org/wiki/%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%94%E0%B8%B3%E0%B9%80%E0%B8%99%E0%B8%B4%E0%B8%99%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%97%E0%B8%A7%E0%B8%B4%E0%B8%A0%E0%B8%B2%E0%B8%84#:~:text=%E0%B9%83%E0%B8%99%E0%B8%97%E0%B8%B2%E0%B8%87%E0%B8%84%E0%B8%93%E0%B8%B4%E0%B8%95%E0%B8%A8%E0%B8%B2%E0%B8%AA%E0%B8%95%E0%B8%A3%E0%B9%8C%20%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%94%E0%B8%B3%E0%B9%80%E0%B8%99%E0%B8%B4%E0%B8%99,%E0%B8%96%E0%B8%B9%E0%B8%81%E0%B9%80%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%81%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%20dyadic">การดำเนินการแบบทวิภาค</a> หรือ <a href="https://en.wikipedia.org/wiki/Binary_operation">Binary Operation</a> (การดำเนินการระหว่าง 2 ตัวดำเนินการ หรือ <a href="https://en.wikipedia.org/wiki/Operand">Operand</a> ใดๆ ในที่นี้ก็คือ การดำเนินการระหว่างค่า Bit 2 ตัว) แบบที่เราเช็คว่ามีตัวใดตัวหนึ่งเป็น 0 หรือไม่ ถ้ามี ผลลัพธ์ก็จะเท่ากับ 0 (0 &amp; 0 = 0, 0 &amp; 1 = 0, 1 &amp; 0 = 0) ซึ่งมี Pattern ว่าถ้าเราเอา 0 ไปดำเนินการผลลัพธ์จะได้เป็น 0 แต่ถ้าเราเอา 1 ไปดำเนินการ ผลลัพธ์จะได้เป็นตัวที่เอามาดำเนินการด้วย (1 &amp; 0 = 0, 1 &amp; 1 = 1)</li><li>| (OR): คือ การดำเนินการแบบทวิภาค แบบที่เราเช็คว่ามีตัวใดตัวหนึ่งเป็น 1 หรือไม่ ถ้ามี ผลลัพธ์ก็จะเท่ากับ 1 (0 | 1 = 1, 1 | 0 = 1, 1 | 1 = 1) ซึ่งมี Pattern ว่าถ้าเราเอา 1 ไปดำเนินการผลลัพธ์จะได้เป็น 1 แต่ถ้าเราเอา 0 ไปดำเนินการ ผลลัพธ์จะได้เป็นตัวที่เอามาดำเนินการด้วย (0 | 0 = 0, 0 | 1 = 1)</li><li>^ (XOR): คือ การดำเนินการแบบทวิภาค แบบที่เราเช็คว่าตัวที่มาดำเนินการมีค่าเหมือนกันหรือไม่ ถ้าเหมือนกัน ผลลัพธ์จะได้เท่ากับ 0 (0 ^ 0 = 0, 1 ^ 1 = 0) ถ้าต่างกัน ผลลัพธ์จะได้เท่ากับ 1 (0 ^ 1 = 1, 1 ^ 0 = 1)</li><li>ส่วนการดำเนินการอื่นๆอย่าง NAND, NOR, XNOR เราสามารถใช้ตัว Bitwise Operation ที่กล่าวไปข้างต้นมาประยุกต์ใช้ได้ เพราะจริงๆแล้ว</li></ul><p>NAND = NOT AND เราสามารถใช้ NOT มาดำเนินการหลังจากการ AND เพื่อทำการใช้ NAND ได้</p><p>NOR = NOT OR เราสามารถใช้ NOT มาดำเนินการหลังจากการ OR เพื่อทำการใช้ NOR ได้</p><p>XNOR = NOT XOR เราสามารถใช้ NOT มาดำเนินการหลังจากการ XOR เพื่อทำการใช้ XNOR ได้ (XNOR จะเหมือนกับการดำเนินการแบบ “ก็ต่อเมื่อ (&lt;-&gt;, If and Only If: Iff)” ในหัวข้อตรรกศาสตร์)</p><ul><li>ลืมไปว่ามี Operators อย่าง “&lt;&lt;” “&gt;&gt;” “&lt;&lt;&lt;” อีก แหะๆ</li><li>&lt;&lt; (Left Shift): คือการเลื่อน Bit แต่ละหลักไปทางหลักทางซ้ายของตัวมันเอง เช่น 0b0101 &lt;&lt; 1 หมายความว่าให้เลื่อนแต่ละ Bit ไปยังหลักทางซ้าย 1 หลักก็จะได้ผลลัพธ์เป็น 0b1010 / หรืออีกตัวอย่าง 0b00100101 &lt;&lt; 2 หมายความว่าให้เลื่องแต่ละ Bit ไปยังหลักทางซ้าย 2 หลักก็จะได้ผลลัพธ์เป็น 0b10010100 สิ่งที่น่าสังเกต คือ การใช้ Left Shift เมื่อมีการย้าย Bit จะทำการเติมเลข 0 ไปในหลักสุดท้ายตามจำนวนการ Shift ที่เรากำหนดด้วย</li><li>&gt;&gt; (Right Shift / Sign-Propagating Right Shift): คือการเลื่อน Bit แต่ละหลักไปทางหลักทางขวาของตัวมันเอง เช่น 0b1100 &gt;&gt; 1 หมายความว่าให้เลื่อนแต่ละ Bit ไปยังหลักทางขวา 1 หลักก็จะได้ผลลัพธ์เป็น 0b11 ข้อสังเกต คือ Right Shift จะไม่มีการเติม 0 เสริมใน Bit และจะมีการคงความเป็นค่าติดลบไว้ในกรณีที่เราใช้ Operator กับค่าที่เป็นติดลบ</li><li>&gt;&gt;&gt; (Unsigned Right Shift / Zero-Filling Right Shift): คือการเลื่อน Bit แต่ละหลักไปทางหลักทางขวาของตัวมันเองเช่นกัน แต่สิ่งที่มันต่างจาก Right Shift แบบเดิมก็คือ มันจะแอบเติม 0 ลง Bit ซ้ายสุด เพื่อทำให้ค่าที่ได้อยู่ในสถานะ Unsigned</li></ul><h3>Bit Flags, Bit Masks, Bit Fields</h3><ul><li>เวลาเราเขียนแทนเลขฐานสองในรูปแบบ 0b&lt;เลขฐานสอง&gt; เป็น Bit เรียงกัน เราจะเรียกว่า Bit Flags (หรือ Bit Masks หรือ Bit Fields) โดยแทน Flag แต่ละตัว หรือ แต่ละ Bit เป็นค่า Boolean ค่าหนึ่ง (0 = false, 1 = true)</li></ul><p>เช่นเราจะเช็ค Permission ในการจัดการกับเนื้อหาในไฟล์ๆหนึ่ง เราอาจจะสามารถเขียนในรูปแบบของ Bit Flag ได้ดังนี้</p><pre>enum Permission = {<br>  CREATE = 0b0001, // Bit หลักที่ 1 เป็น 1 (true) บ่งบอกว่าสามารถ CREATE ได้<br>  READ = 0b0010, // Bit หลักที่ 2 เป็น 1 (true) บ่งบอกว่าสามารถ READ ได้<br>  UPDATE = 0b0100, // Bit หลักที่ 3 เป็น 1 (true) บ่งบอกว่าสามารถ UPDATE ได้<br>  DELETE = 0b1000 // Bit หลักที่ 4 เป็น 1 (true) บ่งบอกว่าสามารถ DELETE ได้<br>};</pre><p>จากโค้ดเราจะเห็นว่า เรากำหนดค่า Boolean ให้กับ Permission แต่ละตัว ด้วยการแทนแต่ละหลักใน Bit Flags เป็นตัวบ่งชี้ Permission แต่ละตัว ตามที่ได้คอมเมนต์เข้าไปในโค้ดข้างต้น</p><p>พอเรากำหนดแบบนี้ได้ หมายความว่าเราก็สามารถทำอะไรได้อีกหลายอย่าง เพราะเรามี Bitwise Operation</p><p>อย่างในกรณีของ Permission เราอาจจะสามารถเอามาใช้แบบนี้ได้</p><pre>function canCreate(userPermission: number): boolean {<br>  return userPermission &amp; Permission.CREATE !== 0;<br>};<br><br>function canRead(userPermission: number): boolean {<br>  return userPermission &amp; Permission.READ !== 0;<br>};<br><br>function canUpdate(userPermission: number): boolean {<br>  return userPermission &amp; Permission.UPDATE !== 0;<br>};<br><br>function canDelete(userPermission: number): boolean {<br>  return userPermission &amp; Permission.DELETE !== 0;<br>};</pre><p>จากโค้ดตัวอย่างข้างต้น เรานำ Bitwise Operator อย่าง &amp; (AND) มาใช้ในการเช็คว่า User Permission อันนี้สามารถกระทำการ Create, Read, Update, Delete ได้หรือเปล่า</p><p>เช่น User Permission อันหนึ่งมีค่าเป็น 0b0111 ถ้าเราพิจารณาจะเห็นว่า หลักที่ 1, 2, 3 ของตัว Permission นี้มีค่าเป็น 1 หมายความว่าสามารถ Create, Read, Update ได้ ในขณะที่หลักที่ 4 มีค่าเป็น 0 หมายความว่าไม่สามารถ Delete ได้</p><p>พอเวลาเราเขียนฟังก์ชันมาเช็ค สมมติว่าเราต้องการจะเช็คว่า สามารถ Create ได้ไหมก็จะเช็คแบบ 0b0111 (User Permission) &amp; 0b0001 (Permission.CREATE) ในที่นี้เราต้องการเช็คแค่การ Create หมายความว่าเราให้หลักอื่นๆนอกเหนือจากหลักที่ 1 มีค่าเป็น 0 ไปได้เลย (ด้วยการ AND กับ Permission.CREATE ที่สนใจแค่หลักที่ 1 แล้วหลักอื่นๆเป็น 0) แล้วเราก็มาดูกันว่าหลักที่ 1 ของ User Permission เป็นเท่าไหร่ ถ้า User Permission หลักที่ 1 เป็น 0 ผลลัพธ์ทั้งหมดก็จะเป็น 0b0000 แปลงเป็นเลขฐานสิบก็จะมีค่าเท่ากับ 0 แต่ถ้าไม่ใช่ ผลลัพธ์ทั้งหมดก็จะเป็น 0b0001 ซึ่งแปลงเป็นเลขฐานสิบก็จะไม่ได้มีค่าเท่ากับ 0 แล้ว เราเลยเอาไปเช็คว่า !== 0 (เท่ากับ 0 ไหม ทั้งโดยค่า และ โดยชนิดของข้อมูล เพื่อความชัวร์) ถ้าไม่เท่ากับ 0 ก็คือมีค่า true หมายความว่า canCreate เป็น true -&gt; User Permission ตัวนี้สามารถ Create ได้ แต่ถ้าเท่ากับ 0 ก็คือ false หมายความว่า canCreate เป็น false -&gt; User Permission ตัวนี้ไม่สามารถ Create ได้ แนะนำว่าลองเอาไปเช็คแบบนี้กับฟังก์ชันอื่นๆดู ใช้หลักคิดเหมือนกัน ต่างกันแค่หลักใน Bit Flags ที่ใช้ในการพิจารณา</p><p>อันนี้เป็นตัวอย่างการใช้ AND มาใช้ทำฟังก์ชันในการช่วยเช็คความสามารถในการ Permission คราวนี้จะลองใช้ OR มาทำการกำหนด Permission ให้กับ User แต่ละแบบกันบ้าง</p><pre>enum User {<br>  ADMIN = Permission.CREATE | Permission.READ | Permission.UPDATE | Permission.DELETE,<br>  EDITOR = Permission.READ | Permission.UPDATE,<br>  VIEWER = Permission.READ <br>};</pre><p>จากตัวอย่างข้างต้น อธิบายไม่ยาก เราแค่ทำการกำหนดว่าจะให้ User แต่ละแบบ มี Permission อะไรบ้าง ก็ง่ายๆเลย เวลาเราใช้ OR มันหมายความว่า ถ้าตัวดำเนินการอย่างน้อยหนึ่งตัวเป็น 1 ผลลัพธ์ก็จะเป็น 1 ซึ่งในโค้ดของเรา การเข้าไปเปิด Permission ก็หมายถึงการแปลงแต่ละหลักที่แทน Permission แต่ละแบบให้เป็น 1 ซึ่งการจะแปลงหลักใดๆให้เป็น 1 แน่นอนว่าวิธีการมันก็คือการเอา 1 เข้าไป OR นั่นแหละ</p><p>อย่างเรากำหนดให้ Editor สามารถ Read (หลักที่ 2) กับ Update (หลักที่ 3) เราจะกำหนด Permission ให้ Editor เราก็ต้องทำให้หลักที่ 2 กับ หลักที่ 3 เป็น 1 ในขณะที่หลักที่เราไม่ต้องการก็ปล่อยให้เป็น 0 ซึ่งวิธีการเราก็แค่เอา Permission.READ กับ Permission.UPDATE มา OR กัน เพราะ Permission.READ กับ Permission.UPDATE เรากำหนด Flag เฉพาะตำแหน่งให้มันเป็น 1 อยู่แล้ว พอเราจะกำหนด Permission ใหม่ที่สามารถ Read, Update ได้ เราก็แค่เอา Permission สองอันนี้มา OR กัน แน่นอนว่าการกำหนด Permission ให้กับ User แบบอื่นๆตามโค้ดข้างต้น ก็ใช้วิธีนี้แหละ</p><p>เดี๋ยวเราจะมาลองยกตัวอย่างการใช้งาน NOT ในการ Remove Permission ออกกันบ้าง</p><pre>function removeCreatePermission(userPermission: number) {<br>  return userPermission &amp; ~Permission.CREATE;<br>};<br><br>function removeReadPermission(userPermission: number) {<br>  return userPermission &amp; ~Permission.READ;<br>};<br><br>function removeUpdatePermission(userPermission: number) {<br>  return userPermission &amp; ~Permission.UPDATE;<br>};<br><br>function removeDeletePermission(userPermission: number) {<br>  return userPermission &amp; ~Permission.DELETE;<br>};</pre><p>จากโค้ดข้างต้น เราต้องการที่จะทำการ Remove Permission บางอย่างออกจาก User Permission ซึ่งวิธีการที่เราจะ Remove นั้นก็คือ การแปลง Flag ในหลักที่ตรงกับ Permission นั้นๆให้เป็น 0</p><p>หมายความว่าสิ่งที่เราต้องทำก็คือ การแปลง Flag ในหลักที่ตรงกับ Permission ที่เราต้องการจะ Remove ให้เป็น 0 ส่วนหลักที่เหลือทำอย่างไรก็ได้ ให้ยังเป็นค่าเดิม ซึ่งเรารู้ว่าจะทำแบบนี้ได้ต้องใช้การ AND</p><p>แล้วเราต้องทำการ AND ตัว User Permission กับอะไรล่ะ ก็อย่างที่บอกว่าสิ่งที่เราต้องการ คือ เราต้องการให้ Permission ในหลักที่ต้องการเป็น 0 ส่วนหลักอื่นๆยังคงเหมือนเดิม เราเลยต้องทำการ NOT ให้กับ Permission ตัวที่เราต้องการ เพื่อที่จะทำให้หลักที่เป็นตัวบ่งชี้ Permission นั้นๆกลายเป็น 0 แล้วหลักอื่นๆกลายเป็น 1 พอเอาไป AND กับ User Permission แล้วจะได้ผลลัพธ์ว่าหลักที่เป็นตัวแทน Permission ที่เราจะ Remove นั้นกลายเป็น 0 แล้ว ส่วนหลักอื่นๆยังคงเหมือนเดิม เพราะเราเอาไป AND กับ 1</p><p>เช่น User Permission คือ 0b0110 หมายความว่า User สามารถ Read, Update ได้ แล้วเราต้องการที่จะ Remove Permission ในการ Update หมายความว่าเราต้องทำให้หลักที่ 2 จากเดิมที่มีค่าเป็น 1 ทำให้กลายเป็น 0 ส่วนหลักที่เหลือก็ให้มีค่าตามเดิม</p><p>จะได้ว่า เราต้องเอา Permission.UPDATE (0b0100) มาทำการ NOT จะได้เป็น ~(Permission.UPDATE) = ~(0b0100) = 0b1011</p><p>พอเอาไป AND กับ User Permission เดิม ก็จะได้ว่า 0b0110 &amp; 0b1011 = 0b0010 ก็คือ User Permission อันใหม่ ที่ทำการเปลี่ยนเลขหลักที่ 2 จาก 1 เป็น 0 ซึ่งก็หมายความว่าเรา Remove ตัว Permission สำหรับการ Update เรียบร้อยแล้วนั่นเอง</p><ul><li>ทีนี้วันก่อนผมได้ไปอ่าน<a href="https://www.facebook.com/photo/?fbid=2774378742736781&amp;set=a.720289284812414">โพสต์ของคุณออม</a> (ผู้สร้าง และ ผู้ดูแลหลักของ <a href="https://elysiajs.com/">ElysiaJS</a>) ที่กล่าวถึงการใช้ Bit Flags แทนการใช้ Boolean ปกติ เพื่อลด <a href="https://en.wikipedia.org/wiki/Overhead_(computing)">Overhead</a> และเพิ่มประสิทธิภาพในการทำงานของตัว Library</li><li>กล่าวคือ Boolean Type ปกติจะกินพื้นที่ 8 Bits (8 / 8 = 1 Byte) ในขณะที่ Bit Flags จะกินพื้นที่ 32 Bits (32 / 8 = 4 Bytes) เพราะ Bit Flags ก็คือ Number Type ที่อยู่ในรูปของเลขฐานสองเฉยๆนั่นแหละ</li><li>แต่เราสามารถเขียน Bit Flags ให้อยู่ในรูปคล้ายๆ Boolean Type ได้ด้วยการกำหนด Bit Flags ที่มี Flag จำนวน 8 ตัว แทนพื้นที่ 8 Bits (1 Byte) ของ Boolean Type นั่นแหละ</li><li>ประเด็นสำคัญที่น่าสนใจจากในโพสต์ของคุณออมที่ยกมาข้างต้นสำหรับผม คือ “การใช้งาน Bit Flags จะกิน Memory มากถ้าใช้ Flag น้อยกว่า 4 ตัว และจะกิน Memory น้อยถ้าใช้ Flag มากกว่า 4 ตัว”</li></ul><h3>ปิดท้าย</h3><p>ขอละการสรุปไว้ประมาณนี้ก่อน ถ้าไม่ขี้เกียจ (ซึ่งส่วนมากขี้เกียจ 55555) จะมา Edit ตัวบทความ Note อันนี้เพิ่มเติมอีกฮะ</p><h3>แหล่งอ้างอิง (References)</h3><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript | MDN (mozilla.org)</a></li><li><a href="https://alexharri.com/blog/bit-sets">Bit Sets: An introduction to bit manipulation (alexharri.com)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6cfa1d39cd27" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[จริงๆแล้วคุณอาจจะเป็น Hidden Gem ของใครสักคน]]></title>
            <link>https://lebrancconvas.medium.com/%E0%B8%88%E0%B8%A3%E0%B8%B4%E0%B8%87%E0%B9%86%E0%B9%81%E0%B8%A5%E0%B9%89%E0%B8%A7%E0%B8%84%E0%B8%B8%E0%B8%93%E0%B8%AD%E0%B8%B2%E0%B8%88%E0%B8%88%E0%B8%B0%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99-hidden-gem-%E0%B8%82%E0%B8%AD%E0%B8%87%E0%B9%83%E0%B8%84%E0%B8%A3%E0%B8%AA%E0%B8%B1%E0%B8%81%E0%B8%84%E0%B8%99-edefa0e10d52?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/edefa0e10d52</guid>
            <category><![CDATA[กำลังใจ]]></category>
            <category><![CDATA[ให้กำลังใจ]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Mon, 22 Jul 2024 16:45:32 GMT</pubDate>
            <atom:updated>2024-07-22T18:04:32.450Z</atom:updated>
            <content:encoded><![CDATA[<p>สวัสดีครับ บทความนี้ผมแค่อยากจะมาบ่นอะไรนิดหน่อยเฉยๆ</p><p>เคยไหมครับที่หลายๆครั้งเรามักจะเจอคอนเทนต์ดีๆ หรือ คนเจ๋งๆที่ยอดวิว ยอดฟอล หรือ มีคนเห็นน้อย หลายครั้งที่ผมมักจะเจอกับคนเหล่านี้ครับ</p><p>เมื่อไม่นานมานี้ผมเลยได้รู้จักคำๆนึงที่ผมได้เห็น ได้ยินแล้ว รู้สึกชอบมากๆ คำๆนั้นคือคำว่า “Hidden Gem”</p><p>คุณอาจจะเป็นเพชรเม็ดงามที่ซ่อนอยู่ในสักที่ที่ไม่มีคนเห็น ใครสักคนจะเห็นคุณได้เขาอาจจะต้องทุ่มใช้แรงกายในการขุดหา ไม่เหมือนกับเพชรที่ถูกนำมาตั้งโชว์เอาไว้</p><p>แต่ถึงอย่างนั้น คุณก็ยังเป็นเพชร</p><p>ผมเลยอยากเขียนบทความนี้ขึ้นมา จริงๆก็คือจะเอามาปลอบใจตัวเอง แล้วก็ถือโอกาสให้กำลังใจกับใครสักคนที่กำลังทำอะไรบางอย่าง หรือ สร้างสรรค์ผลงานอะไรสักอย่าง</p><p>ถ้าเกิดคุณตั้งใจกับงานของตัวเองดีพอ คุณก็คือเพชร ไม่ว่าคุณจะเป็นเพชรที่ถูกนำมาตั้งโชว์ หรือ เป็นเพชรที่ต้องมีใครสักคนขุดหาจนเจอ แต่คุณค่าของคุณ และงานของคุณก็จะส่องประกายอยู่ตรงนั้นอย่างไม่มีวันเสื่อมคลาย :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=edefa0e10d52" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[รวมคำถามน่าสนใจที่เจอใน Technical Interview ที่ผ่านๆมา]]></title>
            <link>https://lebrancconvas.medium.com/%E0%B8%A3%E0%B8%A7%E0%B8%A1%E0%B8%84%E0%B8%B3%E0%B8%96%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%88%E0%B8%B2%E0%B8%AA%E0%B8%99%E0%B9%83%E0%B8%88%E0%B8%97%E0%B8%B5%E0%B9%88%E0%B9%80%E0%B8%88%E0%B8%AD%E0%B9%83%E0%B8%99-technical-interview-%E0%B8%97%E0%B8%B5%E0%B9%88%E0%B8%9C%E0%B9%88%E0%B8%B2%E0%B8%99%E0%B9%86%E0%B8%A1%E0%B8%B2-7d28f87bebcc?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/7d28f87bebcc</guid>
            <category><![CDATA[technical-interview]]></category>
            <category><![CDATA[coding-interviews]]></category>
            <category><![CDATA[interview]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Fri, 14 Jun 2024 13:58:46 GMT</pubDate>
            <atom:updated>2024-06-14T14:40:57.487Z</atom:updated>
            <content:encoded><![CDATA[<h3>รวมคำถามน่าสนใจที่ข้าพเจ้าเจอใน Technical Interview ที่ผ่านๆมา</h3><h3>เขียน Blog นี้ทำไม ?</h3><p>ช่วงนี้เพิ่งเรียนจบ ได้มีโอกาสยื่นที่นู่นที่นี่ ก็มีติดต่อเรียกสัมภาษณ์บ้าง ไม่เรียกบ้างว่ากันไป ประเด็นคือหลายครั้งพอโดนเรียกไปสัมภาษณ์ ก็โดนสัมภาษณ์แบบเชิงเทคนิค ซึ่งบางคำถามที่ทำเราเหวอได้เหมือนกัน คำถามที่เขาเอามาสัมภาษณ์ใน Technical Interview มันเป็นคำถามพื้นฐานที่เราอาจจะยังรู้ไม่ลึก หรือ คืนครูที่สถานศึกษา หรือ ครูอินเตอร์เน็ตไปหมดแล้ว หรือบางคำถามก็อาจจะเป็นอะไรที่เราไม่ค่อยคุ้นเคย เลยอยากจะเอาบันทึกไว้ เปรียบเสมือนบันทึกย้ำเตือนว่ามีอะไรที่เรายังไม่รู้ หรือรู้ไม่ลึก หรือลืมอีกบ้าง เดี๋ยวถ้าไปสัมภาษณ์ที่ไหนแล้วมีคำถามอะไรที่น่าสนใจ หรือที่ไหนที่สัมภาษณ์แล้วนึกคำถามที่น่าสนใจออก จะทยอยเอามาอัพเดทใน Blog นี้นะฮะ :)</p><h3>Linux ต่างกับ Unix อย่างไร ?</h3><p>Linux ถูกสร้างมาในฐานะ Opensource โดยมีแบบมาจาก Unix อีกที (Linux ย่อมาจาก Lovable Intellect Not Using XP (เข้าใจว่าตั้งให้พ้องกับชื่อของเจ้าตัว <a href="https://en.wikipedia.org/wiki/Linus_Torvalds">Linus Torvalds</a> ที่เป็นคนริเริ่มโปรเจค Linux ด้วยแหละ) พี่ที่สัมภาษณ์เล่นมุกว่าย่อมาจาก Linux ย่อมาจาก Linux Is Not UniX 55555+)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7d28f87bebcc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Opinion: AI Art ?]]></title>
            <link>https://lebrancconvas.medium.com/ai-art-is-art-0de8c033004c?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/0de8c033004c</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai-art]]></category>
            <category><![CDATA[generative-ai-use-cases]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Wed, 12 Jun 2024 19:24:05 GMT</pubDate>
            <atom:updated>2024-06-12T20:26:38.241Z</atom:updated>
            <content:encoded><![CDATA[<p>จริงๆ entry นี้ไม่ได้กะจะเขียนอะไรยาวมากมาย แค่ว่าเราไปเจอดราม่าเกี่ยวกับงานภาพที่เกิดจากการใช้ AI ซึ่งส่วนตัวเราขอไม่ไปวิจารณ์กับงานนั้น เพราะเราไม่แน่ใจว่าจริงๆผู้จัดทำเขาใช้กระบวนการแบบไหนในการสร้างสรรค์บ้าง เลยไม่อยากรีบไปตัดสิน</p><p>เราจะพูดถึงความเห็นของเราแค่ว่างานภาพที่สร้างจาก AI มันสมควรถูกนับว่าเป็นศิลปะ ถ้าถามเราส่วนตัวเราว่าการสร้างงานภาพด้วย AI ในทุกวันนี้ มันยังเป็นลักษณะที่เรา Prompt บางอย่าง ซึ่งในบางเครื่องมืออาจจะมีให้ตั้งค่าอะไรบ้าง แต่ส่วนตัวเราก็ยังคิดว่ามันยังต่างงานภาพที่สร้างจากการวาด การถ่ายภาพ หรือแม้แต่การเขียนโค้ดโดยใช้ Graphics Library ตรงที่ว่าไอที่เรายกมาข้างต้น เราสามารถควบคุมรายละเอียดของงานที่ออกมาได้ เราวาดเรารู้ว่าจะลงน้ำหนักเส้น แล้วให้มันออกมาเป็นเส้นอย่างไร หรือ การถ่ายภาพเรายังพอมองเห็นจากหน้ากล้องว่าภาพมันจะออกมาเป็นองค์ประกอบแบบใด หรือแม้แต่การโค้ดที่เรายังพอกำหนดสี และ จุดพิกัดที่จะให้ภาพมันแสดง</p><p>แต่งานภาพที่ถูกสร้างจาก AI เรารู้สึกว่าเรายังไปกำหนดในแบบระดับรายละเอียดไม่ได้ สิ่งที่เราพอทำได้การระบุสิ่งที่เราอยากให้ภาพออกมาแบบคร่าวๆ เราอาจจะมีการ prompt รายละเอียดบางอย่างเข้าไป แต่สุดท้ายมันก็ยังยากที่จะไปกำหนดถึงขนาดว่าให้ค่าสีตรงจุดนี้ออกมาเป็นแบบนี้ สุดท้ายมันเลยเป็นเหมือนบรีฟงานให้ AI แล้วตัวโมเดลมันก็จะประมวลบรีฟที่เราให้มาเป็นภาพอีกที (ผ่านกระบวนการทางคณิตศาสตร์, สถิติ, วิทยาการคอมพิวเตอร์ ที่ถ้าเราอยากเข้าใจมากขึ้นก็ไม่รู้ว่าจะต้องไปงัดกับเปเปอร์วิจัยกี่ฉบับ) เราเลยเห็นด้วยกับความเห็นหลายคนที่บอกว่างานภาพจาก AI ทุกวันนี้ มันเหมือนเราไปจ้างคนอื่นวาดภาพให้ ไม่ได้เหมือนการที่เราไปวาดภาพเองสักทีเดียว</p><p>ถึงจะพูดแบบนั้น แต่ผมก็ยังไม่กล้าที่จะบอกว่างานภาพที่สร้างจาก AI เป็นงานศิลปะหรือไม่ซะทีเดียว เพราะเอาจริงแค่มาตรฐานว่าอะไรคือศิลปะ มันก็ตีความไปได้ร้อยแปด แล้วเอาจริงๆมันก็มีหลายงานที่เอา Generative AI มาใช้แบบไม่ได้ตรงไปตรงมา สุดท้ายก็ขึ้นอยู่กับกึ๋นของผู้สร้างสรรค์งานเหล่านั้นอีกทีหรือเปล่า ?</p><p>ไม่รวมถึงเรื่องของประเด็นเรื่องการนำรูปภาพที่สร้างสรรค์ด้วยมนุษย์มาใช้ในการเทรน ซึ่งก็มีการถกเถียงอีกมากมาย (ผมยังไม่ค่อยอยากไปยุ่งตรงนี้เยอะ เพราะมันมีรายละเอียดอยู่ประมาณนึง) ซึ่งมันก็จะลากยาวไปถึงปัญหาของคนทำงานด้านนี้หลายคนที่เริ่มต้นฝึกปรือตัวเองมาอย่างยาวนาน จนมารู้ว่าสุดท้ายต้องมาเจอกับปัญหาอย่างการกดราคา งานที่ไม่ถูกเห็นค่า ไม่แปลกใจที่หลายคนจะมองว่า AI ที่มาทำงานแบบพวกเขามันมาเร็วเกินไป เจอกับปัญหามามากมาย แล้วเรายังต้องเจอกับอะไรแบบนี้อีกเหรอ ? เลยไม่ค่อยแปลกใจเท่าไหร่ที่กระแสการต่อต้านงานภาพจาก AI มันถึงค่อนข้างรุนแรง</p><p>จริงๆเรามาพ่นความเห็นส่วนตัวเราทิ้งไว้แค่นี้แหละ เหมือนเป็นบันทึกความคิดว่า ณ วันที่เราเหยียบขาทั้งสองข้างในฝั่งวงการศิลปะ และ วงการเทค แต่เป็นการเหยียบที่ยังไม่หยั่งลึกมากพอสักข้าง เรามีความคิดกับประเด็นอย่างไร เราหวังว่าในอนาคตข้างหน้า ถ้าเราได้รับรู้อะไรมามากกว่านี้อีก เราอาจจะมีมุมมองต่อเรื่องนี้ที่กว้างขึ้น ลึกขึ้น</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0de8c033004c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[สรุปหัวข้อตรรกศาสตร์ และ การพิสูจน์  (Logic & Proof)]]></title>
            <link>https://lebrancconvas.medium.com/%E0%B8%AA%E0%B8%A3%E0%B8%B8%E0%B8%9B%E0%B8%AB%E0%B8%B1%E0%B8%A7%E0%B8%82%E0%B9%89%E0%B8%AD%E0%B8%95%E0%B8%A3%E0%B8%A3%E0%B8%81%E0%B8%A8%E0%B8%B2%E0%B8%AA%E0%B8%95%E0%B8%A3%E0%B9%8C-%E0%B9%81%E0%B8%A5%E0%B8%B0-%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%9E%E0%B8%B4%E0%B8%AA%E0%B8%B9%E0%B8%88%E0%B8%99%E0%B9%8C-logic-proof-4f92652e4bfc?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/4f92652e4bfc</guid>
            <category><![CDATA[pure-mathematics]]></category>
            <category><![CDATA[mathematics]]></category>
            <category><![CDATA[mathematical-proof]]></category>
            <category><![CDATA[logic]]></category>
            <category><![CDATA[proof]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Thu, 21 Mar 2024 03:15:02 GMT</pubDate>
            <atom:updated>2024-03-21T03:20:29.712Z</atom:updated>
            <content:encoded><![CDATA[<h3>สรุปหัวข้อตรรกศาสตร์ และ การพิสูจน์ (Logic &amp; Proof) ในทางคณิตศาสตร์</h3><h3>Disclaimer !!</h3><p><em>ตัวผมเองนั้นจัดตัวเองอยู่ในผู้ที่มีความสนใจในคณิตศาสตร์ ไม่ใช่ผู้เชี่ยวชาญ และ ผมอยากจะเขียน Blog นี้ออกมาให้ตัวเอง (และคนอื่น ?) อ่านแล้วเข้าใจได้ไม่ยากให้มากที่สุด ดังนั้นผมจึงไม่สามารถรับประกันในรายละเอียด หรือ ความถูกต้องอย่างถี่ถ้วนภายในบทความได้ วิธีที่ดีที่สุดในการที่คุณจะทำความเข้าใจมันคือ ให้คุณลองเอา Keyword หรือบางอย่างที่ผมเขียนใน Blog นี้ไปค้นหา ศึกษาต่อ หรือ ถ้าใครที่พอมีความรู้ ความเข้าใจมาอ่าน หากมีตรงไหนที่ขาดตกบกพร่อง หรือ อยากเสริม ก็สามารถเข้ามาคอมเมนต์ใน Blog นี้ได้อย่างสะดวก ขออย่างเดียวคือขอให้เราแลกเปลี่ยนกันอย่างเป็นมิตรที่ดีต่อกันก็พอ และผมแนะนำคนที่มาอ่านว่าถ้าหากคุณอ่าน Blog นี้แล้วเจอว่ามันมีคอมเมนต์ ก็แนะนำให้ลองไปอ่านในคอมเมนต์ด้วยเผื่อจะมีคนมาเมนต์ตามที่บอกไปข้างต้น จะได้ทำให้พวกท่านได้รับข้อมูล ความรู้ที่หลากหลาย ครอบคลุมมากขึ้นนะครับ</em> :)</p><h3>เกริ่น</h3><p>เนื่องจากผมได้มีความสนใจอยากจะเขียน Blog เกี่ยวกับเรื่องที่ผมสนใจ ในโอกาสที่ผมได้กลับมาเขียน Blog ใน Medium อีกครั้ง หลังจากเรียนจบ ซึ่งหนึ่งในเรื่องที่ผมสนใจก็คือ คณิตศาสตร์ (Mathematics) โดยเฉพาะสายคณิตศาสตร์บริสุทธิ์ (Pure Mathematics) ซึ่งหัวข้อนึงที่จำเป็น เป็นหัวข้อที่คนที่สนใจคณิตศาสตร์ควรที่จะเรียนรู้เป็นเรื่องแรกๆ เพื่อนำไปใช้ต่อยอดในการศึกษาหัวข้อถัดไป คือ เรื่องตรรกศาสตร์ และ การพิสูจน์ (Logic &amp; Proof) เนื่องจากการศึกษาคณิตศาสตร์โดยมากนั้น เราจะศึกษากันอยู่ภายใต้ นิยาม สัจพจน์ ระบบสัจพจน์ และ ทฤษฎีบท บางอย่างกันเป็นส่วนใหญ่ เราจึงจำเป็นต้องมีความเข้าใจเรื่องการพิสูจน์ เพื่อนำไปต่อยอดในการทำความเข้าใจที่มาของหลายๆทฤษฎีบทในทางคณิตศาสตร์ ในแต่ละหัวข้อได้ครับ</p><h3>เนื้อหา</h3><p>เนื้อหาใน Blog นี้ผมจะทำการเรียบเรียงอยู่เรื่อยๆ แต่เนื่องจากความติดขัดบางประการในการพิมพ์สัญลักษณ์ทางคณิตศาสตร์ใน Medium ใน Draft แรกของ Blog นี้ ผมจะแนบเป็นลิงก์ของ Notion ที่ผมได้ทำการสรุปเรื่องนี้ไว้ก่อนนะครับ</p><p>ลิงก์สรุป: <a href="https://field-week-e72.notion.site/Lecture-Note-Logic-Proof-c0d00a2afbbe465d87b162f9834ac9f5?pvs=4">https://field-week-e72.notion.site/Lecture-Note-Logic-Proof-c0d00a2afbbe465d87b162f9834ac9f5?pvs=4</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f92652e4bfc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lambda Calculus เขาว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ EP.03: Free Variable กับ Combinator]]></title>
            <link>https://lebrancconvas.medium.com/lambda-calculus-%E0%B9%80%E0%B8%82%E0%B8%B2%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%E0%B8%9E%E0%B9%88%E0%B8%AD%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%AA%E0%B8%96%E0%B8%B2%E0%B8%9A%E0%B8%B1%E0%B8%99%E0%B9%81%E0%B8%AB%E0%B9%88%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93-ep-03-free-variable-%E0%B8%81%E0%B8%B1%E0%B8%9A-combinator-1177e77d5c6b?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/1177e77d5c6b</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[theory-of-computation]]></category>
            <category><![CDATA[pure-mathematics]]></category>
            <category><![CDATA[lambda-calculus]]></category>
            <category><![CDATA[mathmatics]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Sat, 24 Feb 2024 13:11:17 GMT</pubDate>
            <atom:updated>2024-02-24T13:11:17.181Z</atom:updated>
            <content:encoded><![CDATA[<h3>Disclaimer !!</h3><p><em>ตัวผมเองนั้นจัดตัวเองอยู่ในผู้ที่มีความสนใจในคณิตศาสตร์ ไม่ใช่ผู้เชี่ยวชาญ และ ผมอยากจะเขียน Blog นี้ออกมาให้ตัวเอง (และคนอื่น ?) อ่านแล้วเข้าใจได้ไม่ยากให้มากที่สุด ดังนั้นผมจึงไม่สามารถรับประกันในรายละเอียด หรือ ความถูกต้องอย่างถี่ถ้วนภายในบทความได้ วิธีที่ดีที่สุดในการที่คุณจะทำความเข้าใจมันคือ ให้คุณลองเอา Keyword หรือบางอย่างที่ผมเขียนใน Blog นี้ไปค้นหา ศึกษาต่อ หรือ ถ้าใครที่พอมีความรู้ ความเข้าใจมาอ่าน หากมีตรงไหนที่ขาดตกบกพร่อง หรือ อยากเสริม ก็สามารถเข้ามาคอมเมนต์ใน Blog นี้ได้อย่างสะดวก ขออย่างเดียวคือขอให้เราแลกเปลี่ยนกันอย่างเป็นมิตรที่ดีต่อกันก็พอ และผมแนะนำคนที่มาอ่านว่าถ้าหากคุณอ่าน Blog นี้แล้วเจอว่ามันมีคอมเมนต์ ก็แนะนำให้ลองไปอ่านในคอมเมนต์ด้วยเผื่อจะมีคนมาเมนต์ตามที่บอกไปข้างต้น จะได้ทำให้พวกท่านได้รับข้อมูล ความรู้ที่หลากหลาย ครอบคลุมมากขึ้นนะครับ</em> :)</p><h3>เกริ่น</h3><p>หลังจากในบทความที่ผ่านมา เราได้พูดถึงพื้นฐาน นิยามของ Lambda Calculus และแสดงให้เห็นภาพของการคำนวณในทาง Lambda Calculus ให้เห็นคร่าวๆแล้ว ผมได้บอกใน<a href="https://lebrancconvas.medium.com/lambda-calculus-%E0%B9%80%E0%B8%82%E0%B8%B2%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%E0%B8%9E%E0%B9%88%E0%B8%AD%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%AA%E0%B8%96%E0%B8%B2%E0%B8%9A%E0%B8%B1%E0%B8%99%E0%B9%81%E0%B8%AB%E0%B9%88%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93-ep-02-%E0%B9%80%E0%B8%A3%E0%B8%B2%E0%B9%80%E0%B8%AD%E0%B8%B2-lambda-calculus-%E0%B8%A1%E0%B8%B2%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B9%84%E0%B8%A3-c9552d9f0480">บทความที่แล้ว</a>แล้วว่า ในบทความนี้ผมจะมาพูดถึงคอนเซปต์ของสิ่งที่เรียกว่า Free Variable และ Combinator ใน Lambda Calculus กันครับ เนื่องจากที่ผมคิดว่าจำเป็นในการทำความเข้าใจ เพื่อที่จะทำให้เราต่อยอดความเข้าใจในประเด็นต่างๆของ Lambda Calculus ได้ดียิ่งขึ้นครับ</p><h3>Free Variable ?</h3><p>นิยามไม่ยากเลยครับ Free Variable จริงๆมันก็คือ</p><blockquote>ตัวแปรที่อยู่ๆก็ไปโผล่ใน Return Expression ของ Abstraction เลย ไม่มีการรับ Parameter แทนค่าตัวแปรนั้นภายใน Abstraction</blockquote><p>ยกตัวอย่างเช่น</p><p>λx.xy</p><p>เราจะเห็นว่า Abstraction ตัวนี้รับ Parameter มาค่าเดียว คือ ค่าตัวแปร x แต่ในขณะที่ใน Return Expression จะมีตัวแปร 2 ตัว คือ ตัวแปร x ที่เรามีการผูกค่ากับ Parameter กับอีกตัวแปรนึงที่อยู่ๆก็ปรากฏออกมาอย่างตัวแปร y ซึ่งเราไม่ได้มีการผูกค่า (Bounded) ตัวแปร y เป็น Parameter</p><p>เราจึงบอกได้ว่าใน Abstraction นี้ ตัวแปร y มีสถานะเป็น Free Variable นั่นเองครับ</p><h3>Combinator ?</h3><p>จริงๆหลักๆในบทความนี้ ผมอยากพูดถึงเรื่อง Combinator เป็นหลักนี่แหละ แต่เราต้องเกริ่นเรื่อง Free Variable ด้วยเพราะว่า นิยามของ Combinator มีความเกี่ยวข้องกับ Free Variable</p><p>นิยามของ Combinator นั้นมีอยู่ว่า…</p><blockquote>Abstraction หรือ Function ที่ไม่มี Free Variable</blockquote><p>นั่นแหละครับ นิยามของ Combinator ง่ายๆสั้นๆแค่นี้เลย</p><p>ยกตัวอย่างของ Abstraction ที่เรานับมันเป็น Combinator ก็เช่น</p><ul><li>λx.λy.x (เขียนรูปย่อได้ว่า λxy.x)</li><li>λx.λy.y (เขียนรูปย่อได้ว่า λxy.y)</li><li>λx.x</li></ul><p>เราจะเห็นได้ว่า Abstraction ที่เรายกตัวอย่างข้างต้น ไม่มีตัวแปรไหนใน Return Expression ที่ไม่ถูกผูกค่าไว้กับ Abstraction Parameter</p><p>มายกตัวอย่างของ Abstraction ที่เราไม่นับมันเป็น Combinator บ้างดีกว่า จะได้เห็นภาพความแตกต่างชัดๆนะครับ</p><ul><li>λx.xy</li><li>λy.x</li><li>λx.y</li><li>λy.xy</li></ul><p>เราจะเห็นว่า Abstraction เหล่านี้จะมีตัวแปรใน Return Expression ที่ไม่มีการผูกค่าไว้กับ Parameter เลยถือว่า Abstraction เหล่านี้มี Free Variable ประกอบอยู่ จึงไม่นับ Abstraction พวกนี้ว่า Combinator นั่นเองครับ</p><h3>Combinator รูปแบบต่างๆ</h3><p>ใน Lambda Calculus จะมีชุดของ Abstraction ชุดนึง ซึ่งอยู่ในรูปของ Combinator ที่มีชื่อเรียกเฉพาะแต่ละแบบ (ใช้ชื่อเป็นชื่อนก น่าสนใจไหมล่ะ) เพื่อเอาไว้ต่อยอดทำความเข้าใจกับเนื้อหา Lambda Calculus ได้อย่างเข้าใจมากขึ้น ในหัวข้อนี้เราจะมายกตัวอย่าง Combinator แต่ละชุด ว่าหมายถึงอะไร เขียนในรูป Lambda Abstraction อย่างไร รวมไปถึงเทียบได้กับการเขียนเป็น Javascript’s Arrow Function ได้อย่างไร และอาจจะมีการลงรายละเอียดแต่ละรูปแบบเล็กน้อยนะครับ</p><h4>Idiot หรือ I-Combinator (Identity)</h4><p>แทนด้วยสัญลักษณ์​ I</p><p><strong>นิยาม</strong></p><p>I := λx.x</p><p><strong>Javascript:</strong></p><pre>const I = x =&gt; x;</pre><p>ความหมายของ Combinator ไอหน้าโง่ (Idiot) นี้ก็คือ Identity Abstraction ที่เราเคยกล่าวไว้แล้วนั่นแหละครับ</p><h4>Kestrel หรือ K-Combinator (True, First)</h4><p>แทนด้วยสัญลักษณ์ K</p><p><strong>นิยาม</strong></p><p>K := λx.λy.x (หรือ λxy.x)</p><p><strong>Javascript:</strong></p><pre>const K = x =&gt; y =&gt; x; </pre><p>ความหมายก็คือ Combinator นี้จะรับ Parameter มาสองตัวตามลำดับ และมันจะ Return ค่าออกมาเป็นค่าของ Parameter ตัวแรกที่มันรับ</p><p>ดูคุ้นๆไหมครับ ?</p><p>ถ้าใครอ่านบทความที่แล้ว ที่เรายกตัวอย่าง Boolean Algebra ภายใต้ Lambda Calculus ไป เราจะเห็นว่านิยามของ Krestel เหมือนกับนิยามของ True นั่นแหละครับ</p><h4>Kite หรือ KI-Combinator (False, Second)</h4><p>แทนด้วยสัญลักษณ์ KI</p><p><strong>นิยาม</strong></p><p>KI := λx.λy.y (หรือ λxy.y)</p><p><strong>Javascript:</strong></p><pre>const KI = x =&gt; y =&gt; y;</pre><p>ความหมายก็คือ Combinator นี้จะรับ Parameter มาสองตัวตามลำดับ และมันจะ Return ค่าออกมาเป็นค่าของ Parameter ตัวที่สองที่มันรับ</p><p>คุ้นๆอีกแล้วไหมครับ ?</p><p>มันคือนิยามเดียวกับ False ในบทความที่แล้วนั่นแหละครับผม</p><h4>Mockingbird หรือ M-Combinator หรือ ω-Combinator (Self-Application)</h4><p>แทนด้วยสัญลักษณ์ M หรือ ω</p><p><strong>นิยาม</strong></p><p>M := λf.ff</p><p><strong>Javascript:</strong></p><pre>const M = f =&gt; f(f); </pre><p>ความหมายก็คือ Combinator จะรับ Parameter มาเป็นค่าฟังก์ชันแทนด้วย f และ Return ค่าอยู่ในรูปฟังก์ชัน f ที่รับ Argument เป็นฟังก์ชัน f อีกที แบบนี้ -&gt; f(f)</p><h4>Cardinal หรือ C-Combinator (Reverse Arguments)</h4><p>แทนด้วยสัญลักษณ์ C</p><p><strong>นิยาม</strong></p><p>C := λf.λx.λy.fyx หรือ λfxy.fyx</p><p><strong>Javascript:</strong></p><pre>const C = f =&gt; x =&gt; y =&gt; f(y)(x); </pre><p>ความหมายก็คือ Combinator ตัวนี้จะรับตัวแปรสามตัว แล้วคืนค่าเป็น ตัวแปรตัวแรกที่ทำหน้าที่เป็นฟังก์ชันที่รับ Argument เป็นตัวแปรตัวที่สาม กับ ตัวแปรตัวที่สอง ตามลำดับแบบ Currying</p><h4>Thrush หรือ T-Combinator</h4><p>แทนด้วยสัญลักษณ์ T</p><p><strong>นิยาม</strong></p><p>T := λa.λb.ba หรือ λab.ba</p><p><strong>Javascript:</strong></p><pre>const T = a =&gt; b =&gt; b(a); </pre><p>ความหมายก็คือ Combinator ตัวนี้จะรับตัวแปรมาสองตัว แล้วคืนค่าเป็นตัวแปรตัวที่สองที่ทำหน้าที่เป็นฟังก์ชันที่รับ argument เป็นตัวแปรตัวแรก</p><h4>Bluebird หรือ B-Combinator (Function Composition)</h4><p>แทนด้วยสัญลักษณ์ B</p><p><strong>นิยาม</strong></p><p>B := λf.λg.λx.f(gx) หรือ λfgx.f(gx)</p><p><strong>Javascript:</strong></p><pre>const B = f =&gt; g =&gt; x=&gt; f(g(x));</pre><p>ความหมายก็คือ Combinator ตัวนี้จะรับตัวแปรมาสามตัว แล้วคืนค่าเป็นตัวแปรตัวแรกที่ทำหน้าที่เป็นฟังก์ชันที่รับ Argument เป็นตัวแปรตัวที่สองที่ทำหน้าที่เป็นฟังก์ชันที่รับ Argument เป็นตัวแปรตัวที่สามอีกที</p><p>ถ้าเราสังเกตรูปแบบที่ถูก Return มา เราจะเห็นว่ามันเหมือนกับการทำ Function Composition ระหว่าง f (ตัวแปรตัวแรกที่รับมา) กับ g (ตัวแปรตัวที่สองที่รับมา)</p><h4>Vireo หรือ V-Combinator</h4><p>แทนด้วยสัญลักษณ์ V</p><p><strong>นิยาม</strong></p><p>V := λa.λb.λf.fab หรือ λabf.fab</p><p><strong>Javascript:</strong></p><pre>const V = a =&gt; b =&gt; f =&gt; f(a)(b); </pre><p>ความหมายก็คือ Combinator ตัวนี้จะรับตัวแปรมาสามตัว แล้วคืนค่าเป็นตัวแปรตัวที่สามที่ทำหน้าที่เป็นฟังก์ชันที่รับ Argument เป็นตัวแปรตัวที่หนึ่ง และ ตัวแปรตัวที่สองแบบ Currying</p><p>(Combinator หลังจากนี้ผมอาจจะไม่ได้ขยายความเพิ่ม เพราะคิดว่าเริ่มมีความซับซ้อนขึ้นนิดนึง ผมคิดว่าทำความเข้าใจผ่าน Lambda Abstraction เทียบกับ Javascript Syntax ไปเลยดีกว่า)</p><h4>Hummingbird หรือ H-Combinator</h4><p>แทนด้วยสัญลักษณ์ H</p><p><strong>นิยาม</strong></p><p>H := λa.λb.λc.abcb หรือ λabc.abcb</p><p><strong>Javascript:</strong></p><pre>const H = a =&gt; b =&gt; c =&gt; a(b)(c)(b); </pre><h4>Eagle หรือ E-Combinator</h4><p>แทนด้วยสัญลักษณ์ B</p><p><strong>นิยาม</strong></p><p>E := λa.λb.λc.λd.λe.ab(cde) หรือ λabcde.ab(cde)</p><p><strong>Javascript:</strong></p><pre>const E = a =&gt; b =&gt; c =&gt; d =&gt; e =&gt; a(b(c(d)(e))); </pre><h4>Lark หรือ L-Combinator</h4><p>แทนด้วยสัญลักษณ์ L</p><p><strong>นิยาม</strong></p><p>L := λa.λb.a(bb) หรือ λab.a(bb)</p><p><strong>Javascript:</strong></p><pre>const L = a =&gt; b =&gt; a(b(b)) </pre><h4>Owl หรือ O-Combinator</h4><p>แทนด้วยสัญลักษณ์ O</p><p><strong>นิยาม</strong></p><p>O := λa.λb.b(ab) หรือ λab.b(ab)</p><p><strong>Javascript:</strong></p><pre>const O = a =&gt; b =&gt; b(a(b)); </pre><h4>Robin หรือ R-Combinator</h4><p>แทนด้วยสัญลักษณ์ R</p><p><strong>นิยาม</strong></p><p>R := λa.λb.λc.bca หรือ λabc.bca</p><p><strong>Javascript:</strong></p><pre>const R= a =&gt; b =&gt; c =&gt; b(c)(a); </pre><h4>Starling หรือ S-Combinator</h4><p>แทนด้วยสัญลักษณ์ S</p><p><strong>นิยาม</strong></p><p>S := λa.λb.λc.ac(bc) หรือ λabc.ac(bc)</p><p><strong>Javascript:</strong></p><pre>const S = a =&gt; b =&gt; c =&gt; a(c)(b(c)); </pre><h4>Warbler หรือ W-Combinator</h4><p>แทนด้วยสัญลักษณ์ W</p><p><strong>นิยาม</strong></p><p>W := λa.λb.abb หรือ λab.abb</p><p><strong>Javascript:</strong></p><pre>const W = a =&gt; b =&gt; a(b)(b);</pre><h4>Queer หรือ Q-Combinator</h4><p>แทนด้วยสัญลักษณ์ Q</p><p><strong>นิยาม</strong></p><p>Q := λa.λb.λc.b(ac) หรือ λabc.b(ac)</p><p><strong>Javascript:</strong></p><pre>const Q = a =&gt; b =&gt; c =&gt; b(a(c)); </pre><h4>Finch หรือ F-Combinator</h4><p>แทนด้วยสัญลักษณ์ F</p><p><strong>นิยาม</strong></p><p>F := λa.λb.λc.cba หรือ λabc.cba</p><p><strong>Javascript:</strong></p><pre>const F = a =&gt; b =&gt; c =&gt; c(b)(a); </pre><h4>Goldfinch หรือ G-Combinator</h4><p>แทนด้วยสัญลักษณ์ G</p><p><strong>นิยาม</strong></p><p>G := λa.λb.λc.λd.ad(bc) หรือ λabcd.ad(bc)</p><p><strong>Javascript:</strong></p><pre>const G = a =&gt; b =&gt; c =&gt; d =&gt; a(d)(b(c)); </pre><h4>Dove หรือ D-Combinator</h4><p>แทนด้วยสัญลักษณ์ D</p><p><strong>นิยาม</strong></p><p>D := λa.λb.λc.λd.ab(cd) หรือ λabcd.ab(cd)</p><p><strong>Javascript:</strong></p><pre>const D = a =&gt; b =&gt; c =&gt; d =&gt; a(b)(c(d)); </pre><h4>Apply หรือ A-Combinator</h4><p>แทนด้วยสัญลักษณ์ A</p><p><strong>นิยาม</strong></p><p>A := λa.λb.ab หรือ λab.ab</p><p><strong>Javascript:</strong></p><pre>const A = a =&gt; b =&gt; a(b); </pre><h4>BlackBird หรือ BB-Combinator</h4><p>แทนด้วยสัญลักษณ์ BB</p><p><strong>นิยาม</strong></p><p>BB := λa.λb.λc.λd.a(bcd) หรือ λabcd.a(bcd)</p><p><strong>Javascript:</strong></p><pre>const BB = a =&gt; b =&gt; c =&gt; d =&gt; a(b(c(d))); </pre><h4>Phoenix หรือ P-Combinator</h4><p>แทนด้วยสัญลักษณ์ P</p><p><strong>นิยาม</strong></p><p>P := λa.λb.λc.λd.a(bd)(cd) หรือ λabcd.a(bd)(cd)</p><p><strong>Javascript:</strong></p><pre>const P = a =&gt; b =&gt; c =&gt; d =&gt; a(b(c))(c(d)); </pre><h4>Z Fixed-Point หรือ Z-Combinator</h4><p>แทนด้วยสัญลักษณ์ Z</p><p><strong>นิยาม</strong></p><p>Z := λa.M(λb(a(Mb))) // M ในที่นี่หมายถึง M-Combinator หรือ Mockingbird นั้นเอง</p><p><strong>Javascript:</strong></p><pre>const Z = a =&gt; M(b =&gt; a(M(b))); </pre><h4>Turing หรือ U-Combinator</h4><p>แทนด้วยสัญลักษณ์ U</p><p><strong>นิยาม</strong></p><p>U := λa.λb.b(aab) หรือ λab.b(aab)</p><p><strong>Javascript:</strong></p><pre>const U = a =&gt; b =&gt; b(a(a)(b)); </pre><h4>Psi หรือ Ψ-Combinator</h4><p>แทนด้วยสัญลักษณ์ Ψ</p><p><strong>นิยาม</strong></p><p>Ψ := λa.λb.λc.λd.a(bc)(bd) หรือ λabcd.a(bc)(bd)</p><p><strong>Javascript:</strong></p><pre>const Psi = a =&gt; b =&gt; c =&gt; d =&gt; a(b(c))(b(d));</pre><h3>สรุป</h3><p>ในบทความนี้เราพูดถึง Free Variable ที่หมายถึงตัวแปรที่ปรากฏใน Return Expression ของ Abstraction แต่ไม่ได้ถูกผูกไว้กับ Parameter ของ Abstraction ในขณะที่ Combinator หมายถึง Abstraction ที่ไม่มี Free Variable</p><p>ซึ่งเราก็ได้มีการยกตัวอย่าง Combinator แบบต่างๆที่จะนำมาใช้ช่วยในการอธิบายในหัวข้อต่างๆของ Lambda Calculus ที่จะพูดถึงต่อๆไปด้วย (ยังมี Combinator อีก หลายตัวที่ไม่ได้พูดถึงในบทความนี้ แนะนำให้ลองค้นหาผ่านทางแหล่งอ้างอิงที่ผมแนบท้ายบทความนี้ หรือจะค้นหาในแหล่งข้อมูลเพิ่มเติมนอกเหนือจากนี้ก็ได้)</p><p>เพียงแต่ว่าจริงๆแล้วเรายังมี Combinator ตัวเด็ดอีกรูปแบบหนึ่งที่เราต้องพูดถึง แต่ยังไม่ได้พูดถึงในบทความนี้ นั่นก็คือ Y-Combinator ซึ่งเราจะขอแยกไปพูดถึง Combinator ตัวนี้ในบทความถัดไป เพราะเราจะพูดถึงสิ่งที่เรียกว่าการวนซ้ำ (Recursion) ภายใต้กฏของ Lambda Calculus ซึ่งมีความเกี่ยวข้องกับเจ้า Y-Combinator นี้ด้วย</p><h3>แหล่งอ้างอิง (References)</h3><ul><li><a href="http://hi.gher.space/wiki/Lambda_calculus">Lambda calculus — Hi.gher. Space</a></li><li><a href="https://www.youtube.com/watch?v=3VQ382QG-y4">Lambda Calculus — Fundamentals of Lambda Calculus &amp; Functional Programming in JavaScript (youtube.com)</a></li><li><a href="https://github.com/loophp/combinator">loophp/combinator: A curated list of combinators (github.com)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1177e77d5c6b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lambda Calculus เขาว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ EP.02: เราเอา Lambda Calculus มาคำนวณอย่างไร ?]]></title>
            <link>https://lebrancconvas.medium.com/lambda-calculus-%E0%B9%80%E0%B8%82%E0%B8%B2%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%E0%B8%9E%E0%B9%88%E0%B8%AD%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%AA%E0%B8%96%E0%B8%B2%E0%B8%9A%E0%B8%B1%E0%B8%99%E0%B9%81%E0%B8%AB%E0%B9%88%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93-ep-02-%E0%B9%80%E0%B8%A3%E0%B8%B2%E0%B9%80%E0%B8%AD%E0%B8%B2-lambda-calculus-%E0%B8%A1%E0%B8%B2%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B9%84%E0%B8%A3-c9552d9f0480?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9552d9f0480</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[lambda-calculus]]></category>
            <category><![CDATA[pure-mathematics]]></category>
            <category><![CDATA[mathematics]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Sun, 18 Feb 2024 22:17:41 GMT</pubDate>
            <atom:updated>2024-02-24T13:02:53.158Z</atom:updated>
            <content:encoded><![CDATA[<h3>Lambda Calculus เขาว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ EP.02: เราเอา Lambda Calculus มาคำนวณอย่างไร ?</h3><h3>Disclaimer !!</h3><p><em>ตัวผมเองนั้นจัดตัวเองอยู่ในผู้ที่มีความสนใจในคณิตศาสตร์ ไม่ใช่ผู้เชี่ยวชาญ และ ผมอยากจะเขียน Blog นี้ออกมาให้ตัวเอง (และคนอื่น ?) อ่านแล้วเข้าใจได้ไม่ยากให้มากที่สุด ดังนั้นผมจึงไม่สามารถรับประกันในรายละเอียด หรือ ความถูกต้องอย่างถี่ถ้วนภายในบทความได้ วิธีที่ดีที่สุดในการที่คุณจะทำความเข้าใจมันคือ ให้คุณลองเอา Keyword หรือบางอย่างที่ผมเขียนใน Blog นี้ไปค้นหา ศึกษาต่อ หรือ ถ้าใครที่พอมีความรู้ ความเข้าใจมาอ่าน หากมีตรงไหนที่ขาดตกบกพร่อง หรือ อยากเสริม ก็สามารถเข้ามาคอมเมนต์ใน Blog นี้ได้อย่างสะดวก ขออย่างเดียวคือขอให้เราแลกเปลี่ยนกันอย่างเป็นมิตรที่ดีต่อกันก็พอ และผมแนะนำคนที่มาอ่านว่าถ้าหากคุณอ่าน Blog นี้แล้วเจอว่ามันมีคอมเมนต์ ก็แนะนำให้ลองไปอ่านในคอมเมนต์ด้วยเผื่อจะมีคนมาเมนต์ตามที่บอกไปข้างต้น จะได้ทำให้พวกท่านได้รับข้อมูล ความรู้ที่หลากหลาย ครอบคลุมมากขึ้นนะครับ</em> :)</p><h3>เกริ่น</h3><p>หลังจาก <a href="https://lebrancconvas.medium.com/lambda-calculus-%E0%B9%80%E0%B8%82%E0%B8%B2%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%E0%B8%9E%E0%B9%88%E0%B8%AD%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%AA%E0%B8%96%E0%B8%B2%E0%B8%9A%E0%B8%B1%E0%B8%99%E0%B9%81%E0%B8%AB%E0%B9%88%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93-ep-01-14412c850bf1">Blog ที่แล้ว</a> เราได้พูดถึงรูปแบบพื้นฐานของ Lambda Calculus ในบทความนี้เราจะมาลงรายละเอียดให้เห็นการคำนวณโดยใช้ Lambda Calculus กันว่า ปัญหาทางคณิตศาสตร์แบบต่างๆ สามารถเอามาดำเนินการในรูปแบบของ Lambda Calculus ได้อย่างไร</p><h3>ใครๆเขาก็ยกตัวอย่าง Boolean Algebra กันก่อนทั้งนั้นแหละ</h3><p>หลายๆบทความรวมถึงบทความนี้ด้วย จะยกตัวอย่างการคำนวณในรูปแบบ Lambda Calculus ผ่านโจทย์ของ <a href="https://en.wikipedia.org/wiki/Boolean_algebra">Boolean Algebra</a> (ค่า True, False และการดำเนินการ AND, OR, NOT) กันก่อน เนื่องจากเราสามารถทำความเข้าใจกับมันได้ง่าย</p><p>ใน Lambda Calculus เราจะถือว่า True, False, AND, OR, NOT เป็นตัวแปร (Variable) ที่เราสามารถแทนที่ได้ด้วย Expression บางอย่างที่ถูกกำหนดไว้ โดยตัวแปรเหล่านี้จะมี Expression ที่อยู่ในรูปของ Lambda Calculus ดังนี้</p><p>True := λx.λy.x (ตีความได้ว่าหากเราแทนค่าของ x และ y ใน Abstraction นี้ได้ ผลลัพธ์ที่ได้จะเป็นค่าที่แทนให้กับ x)</p><p>False := λx.λy.y (ตีความได้ว่าหากเราแทนค่าของ x และ y ใน Abstraction นี้ได้ ผลลัพธ์ที่ได้จะเป็นค่าที่แทนให้กับ y)</p><p>NOT := λx.x False True (ตีความได้ว่าหากเราแทนค่าของ x ใน Abstraction นี้ได้ ผลลัพธ์ที่ได้จะอยู่ในรูป Expression ที่เป็น &lt;ค่าที่แทนให้ x&gt; False True)</p><p>AND := λx.λy.x y False</p><p>OR := λx.λy.x TRUE y</p><h4>ตัวอย่าง</h4><ul><li>NOT True</li></ul><p>ตอนนี้โจทย์อยู่ในรูปแบบของตัวแปรสองตัว (NOT กับ True) กำลังถูกเรียงกันแบบ Application แต่เราไม่สามารถเอา True ไปดำเนินการกับ NOT ได้เนื่องจากตอนนี้ NOT เป็นแค่ตัวแปร ไม่ใช่ Abstraction</p><p>เราก็แค่ต้องแปลงตัวแปรด้านซ้าย หรือในโจทย์นี้ก็คือ NOT ให้เป็น Expression ที่อยู่ในรูป Abstraction นั่นก็คือ</p><p>(λx.x False True) True **เราใส่วงเล็บเพื่อทำการ Grouping ตัว Expression ให้เห็นว่าเป็น Expression กลุ่มเดียวกัน**</p><p>จะเห็นว่าตอนนี้เราแปลงตัวแปรด้านซ้ายให้เป็น Abstraction แล้ว ทีนี้เราก็เอาตัวแปรทางขวา ไปแทนใน Abstraction ด้านซ้ายตามหลักของ Application ได้เลย ก็จะได้ออกมาเป็น</p><p>λTrue.True False True =&gt; True False True</p><p>ตอนนี้เราได้ผลลัพธ์ออกมาเป็น True False True ซึ่งยังไม่ใช่ผลลัพธ์แบบที่เราต้องการ เนื่องจากมันยังอยู่ในรูปของตัวแปรสามตัวเรียงกัน</p><p><em>(เราต้องการผลลัพธ์ให้อยู่ในรูปของตัวแปร หรือ การดำเนินการที่ถูกย่อที่สุดเท่าที่จะเป็นไปได้ โดยเราจะเรียกผลลัพธ์สุดท้ายของการดำเนินการทาง Lambda Calculus ว่า </em><a href="https://en.wikipedia.org/wiki/Beta_normal_form"><em>β-Normal Form</em></a><em> อ่านว่า Beta Normal Form โดยวิธีการคำนวณโดยการย่อรูปแบบของโจทย์ ผ่านการแทนที่ (Substituting) Abstraction ด้วยตัวแปรที่เรียงในรูป Application ดังที่ยกตัวอย่างไปข้างบนว่า </em><a href="https://www.educative.io/answers/what-is-beta-reduction-in-lambda-calculus"><em>β-Reduction</em></a><em> อ่านว่า Beta Reduction ซึ่งนี่ถือเป็นหัวใจของการคำนวณใน Lambda Calculus เลยครับ)</em></p><p>โอเค แก้โจทย์กันต่อ…</p><p>แน่นอนว่าพอเราเจอตัวแปรเรียงกัน เราก็จะใช้วิธีการแปลงตัวแปรตัวซ้ายสุด ให้อยู่ในรูป Abstraction ตามที่กำหนดไว้ ก็จะได้เป็น</p><p>(λx.λy.x) False True</p><p>เยี่ยม! เราได้ Abstraction ที่ซ้อนค่า Parameter 2 ค่า และเรามีตัวแปร 2 ตัว เรียงกันด้านขวาพอดี จริงๆเราสามารถลัดขั้นตอนด้วยการแทน x เป็น False แทน y เป็น True เลยก็ได้ แต่ผมอยากแสดงให้เห็นเป็นขั้นเป็นตอน เพื่อให้เห็นการดำเนินการของ Lambda Calculus ที่ชัดเจน ก็จะได้เป็น</p><p>=&gt; (λx.λy.x) False True</p><p>=&gt; (λFalse.λy.False) True</p><p>=&gt; (λy.False) True</p><p>=&gt; λTrue.False</p><p>=&gt; False</p><p>เราได้ผลลัพธ์ออกมาเป็นตัวแปรตัวเดียวนั่นก็คือ False ซึ่งอยู่ในรูป<em> </em><a href="https://en.wikipedia.org/wiki/Beta_normal_form">β-Normal Form</a> ตามที่เราต้องการแล้ว</p><p>สังเกตอะไรไหมครับ ?</p><p>โจทย์ของเราคือ NOT True เอามาคำนวณแล้วได้ผลลัพธ์เป็น False</p><p>มันเหมือนกับการคำนวณแบบ Boolean Algebra ตามปกติเลย เอาค่า True มาดำเนินการ Not ได้ผลลัพธ์เป็น False</p><p>นี่แหละครับ ตัวอย่างที่ทำไมผมถึงบอกว่าการคำนวณแบบปกติ ถึงสามารถเอามาเขียนเป็นรูปของ Lambda Calculus แล้วยังได้ผลลัพธ์ที่เหมือนกัน ทั้งๆที่ใน Lambda Calculus เรามองทุกอย่างเป็นตัวแปร แล้วก็แค่ทำการแทนที่ ลดรูป วนไปเรื่อยๆ</p><ul><li>OR False True</li></ul><p>โอเค เรามาถึงตัวอย่างถัดไปละครับ สนใจลองทำเองดูไหมครับ</p><p>เดี๋ยวผมจะเขียนวิธีการทำแบบไม่ลงรายละเอียด (ขี้เกียจ) ไว้ข้างล่างนะครับ</p><p>=&gt; OR False True</p><p>=&gt; (λx.λy.x True y) False True</p><p>=&gt; (λFalse.λy.False True y) True</p><p>=&gt; (λy.False True y) True</p><p>=&gt; λTrue.False True True</p><p>=&gt; False True True</p><p>=&gt; (λx.λy.y) True True</p><p>=&gt; (λTrue.λy.y) True</p><p>=&gt; λTrue.λTrue.True</p><p>=&gt; True</p><p>พอจะเก็ตขั้นตอนไหมครับ ? ผมแนะนำให้ลองทำความเข้าใจแต่ละบรรทัดดูนะ</p><p>เราก็จะได้ว่า OR False True ได้ผลลัพธ์ออกมาเป็น True ซึ่งก็ได้ผลลัพธ์เหมือนกับการเอา False กับ True มาดำเนินการ or กันแบบ Boolean Algebra เลยใช่ไหมครับ</p><p>ถ้าใครพอเข้าใจการดำเนินการทาง Lambda Calculus ผ่านสองตัวอย่างนี้ ก็ลองทำความเข้าใจกับ AND True False, AND False True, AND True True, AND False False, OR True False, OR False False, OR True True, NOT False ที่ผมไม่ได้ยกเป็นตัวอย่างดูครับ ว่าได้ผลลัพธ์ออกมาตามคาดหรือเปล่า</p><h3>มี Beta ก็ต้องมี Alpha</h3><p>จากตัวอย่างของการคำนวณผ่านรูปแบบ Lambda Calculus ไว้ข้างบน ผมได้พูดถึง β-Reduction ที่หมายถึง การคำนวณด้วยการแทนที่ และ ลดรูปไปเรื่อยๆจนเหลือตัวแปรเดียว หรือ อยู่ในรูปที่ไม่สามารถลดได้อีกแล้ว หรือที่เราเรียกว่า β-Normal Form เลยอยากจะพูดถึงอีกคีย์เวิร์ดที่สำคัญก็คือ <a href="https://opendsa.cs.vt.edu/ODSA/Books/PL/html/AlphaConversion.html">α-Conversion</a> (อ่านว่า Alpha Conversion)</p><p>ผมยกตัวอย่าง Lambda Abstraction ตัวนี้</p><p>λx.x</p><p>ตัวอย่าง Basic ดีไหมครับ ^^</p><p>ถ้าเราสังเกต Abstraction ตัวนี้จะเห็นว่ามันเป็น Abstraction ที่รับ Parameter ตัวนึงแทนด้วย x แล้วก็ Return ค่าออกมาเป็น Parameter ตัวนั้น</p><p>Abstraction รูปแบบนี้เราเรียกมันว่า <strong>Identity Abstraction</strong> หรือ <strong>Identity Function</strong> ครับ</p><p>แต่ประเด็นที่ผมจะพูดถึงจริงๆก็คือ ถ้าเกิดเราเปลี่ยนชื่อตัวแปรจาก x เป็น y ทั้ง Abstraction นี้ล่ะ ก็จะได้เป็น</p><p>λy.y</p><p>จะเห็นว่าตัวแปรถูกเปลี่ยน แต่ความหมายของ Abstraction นี้ก็ยังคงเป็น Abstraction ที่รับ Parameter มาตัวนึง แล้ว Return ค่าเป็น Parameter ตัวนั้นอยู่ดี และไม่ว่าเราจะเปลี่ยนชื่อตัวแปรเป็น λz.z มันก็จะยังมีความหมายเดิมอยู่ดี</p><p>เราเรียกการเปลี่ยนชื่อตัวแปรใน Abstraction แต่ยังได้ Abstraction ที่มีลักษณะการทำงานเหมือนเดิมว่า <a href="https://opendsa.cs.vt.edu/ODSA/Books/PL/html/AlphaConversion.html">α-Conversion</a> นี่แหละครับ</p><h3>สรุป</h3><p>จริงๆการคำนวณของ Lambda Calculus มันคือการแทนที่ตัวแปรด้วย Expression ตามที่ถูกกำหนดไว้ แล้วลดรูป แล้วก็แทนที่ ลดรูปไปเรื่อยๆจนได้เป็นผลลัพธ์ที่อาจจะอยู่ในรูปๆหนึ่ง หรือ ค่าๆหนึ่งเฉยๆ ซึ่งการคำนวณรูปแบบนี้จะใช้ได้กับอีกหลายๆการคำนวณทางคณิตศาสตร์เลย ไม่ใช่แค่ Boolean Algebra แต่รวมไปถึง Algebra ทั่วๆไปอย่างการบวก การลบ การคูณ การหารจำนวนเลย</p><p>แต่ก่อนที่เราจะไปลงลึกการใช้ Lambda Calculus ในการคำนวณตัวเลข (ซึ่งจะดูงง และ ซับซ้อนขึ้นกว่านี้มาก ๑_๑) ผมอยากจะแนะนำคอนเซปต์ของสิ่งที่เรียกว่า Free Variable กับ Combinator รวมไปถึง Combinator ในรูปแบบต่างๆ งงล่ะสิอยู่ๆมีคำอะไรโผล่ออกมาอีกก็ไม่รู้ มีรูปแบบต่างๆด้วย ถ้าคุณอยากรู้ก็ติดตามชมบทความต่อไปให้ดีล่ะครับ ขอบคุณครับ</p><h3>แหล่งอ้างอิง (References)</h3><ul><li><a href="https://www.youtube.com/watch?v=3VQ382QG-y4">Lambda Calculus — Fundamentals of Lambda Calculus &amp; Functional Programming in JavaScript (youtube.com)</a></li><li><a href="https://www.tamemo.com/post/153/lambda-calculus/">Lambda Calculus ~ พื้นฐานสู่ Functional Programming — TAmemo.com</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9552d9f0480" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lambda Calculus เขาว่ากันว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ EP.01:]]></title>
            <link>https://lebrancconvas.medium.com/lambda-calculus-%E0%B9%80%E0%B8%82%E0%B8%B2%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B8%A7%E0%B9%88%E0%B8%B2%E0%B9%80%E0%B8%9B%E0%B9%87%E0%B8%99%E0%B8%9E%E0%B9%88%E0%B8%AD%E0%B8%97%E0%B8%B8%E0%B8%81%E0%B8%AA%E0%B8%96%E0%B8%B2%E0%B8%9A%E0%B8%B1%E0%B8%99%E0%B9%81%E0%B8%AB%E0%B9%88%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%84%E0%B8%B3%E0%B8%99%E0%B8%A7%E0%B8%93-ep-01-14412c850bf1?source=rss-84e1e2001f4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/14412c850bf1</guid>
            <category><![CDATA[lambda-calculus]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[mathematics]]></category>
            <category><![CDATA[pure-mathematics]]></category>
            <category><![CDATA[math]]></category>
            <dc:creator><![CDATA[Poom Yimyuean]]></dc:creator>
            <pubDate>Sun, 18 Feb 2024 16:10:06 GMT</pubDate>
            <atom:updated>2024-05-26T19:17:26.397Z</atom:updated>
            <content:encoded><![CDATA[<h3>Lambda Calculus เขาว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ EP.01: นิยาม และองค์ประกอบพื้นฐานของ Lambda Calculus</h3><h3>Disclaimer !!</h3><p><em>ตัวผมเองนั้นจัดตัวเองอยู่ในผู้ที่มีความสนใจในคณิตศาสตร์ ไม่ใช่ผู้เชี่ยวชาญ และ ผมอยากจะเขียน Blog นี้ออกมาให้ตัวเอง (และคนอื่น ?) อ่านแล้วเข้าใจได้ไม่ยากให้มากที่สุด ดังนั้นผมจึงไม่สามารถรับประกันในรายละเอียด หรือ ความถูกต้องอย่างถี่ถ้วนภายในบทความได้ วิธีที่ดีที่สุดในการที่คุณจะทำความเข้าใจมันคือ ให้คุณลองเอา Keyword หรือบางอย่างที่ผมเขียนใน Blog นี้ไปค้นหา ศึกษาต่อ หรือ ถ้าใครที่พอมีความรู้ ความเข้าใจมาอ่าน หากมีตรงไหนที่ขาดตกบกพร่อง หรือ อยากเสริม ก็สามารถเข้ามาคอมเมนต์ใน Blog นี้ได้อย่างสะดวก ขออย่างเดียวคือขอให้เราแลกเปลี่ยนกันอย่างเป็นมิตรที่ดีต่อกันก็พอ และผมแนะนำคนที่มาอ่านว่าถ้าหากคุณอ่าน Blog นี้แล้วเจอว่ามันมีคอมเมนต์ ก็แนะนำให้ลองไปอ่านในคอมเมนต์ด้วยเผื่อจะมีคนมาเมนต์ตามที่บอกไปข้างต้น จะได้ทำให้พวกท่านได้รับข้อมูล ความรู้ที่หลากหลาย ครอบคลุมมากขึ้นนะครับ</em> :)</p><h3>เกริ่น</h3><p>เนื่องจากว่าผมได้มีโอกาสมาศึกษา Functional Programming อย่างจริงจังด้วยความเนิร์ดส่วนตัวที่เห็นว่ามันเป็นศาสตร์คอมพิวเตอร์ที่มีการหยิบยืมคอนเซปต์ของ Pure Mathematics มาใช้อย่างจัดเต็มประมาณนึง บวกกับเห็นโอกาสหลายๆอย่างในแวดวง Software Developer / Computer Science ในยุคปัจจุบัน ถ้าหากมีความเข้าใจ Functional Programming หรือ Functional Programming Language เลยคิดว่าศึกษามันอย่างจริงจังไปเลยดีกว่า</p><p>หลังจากที่ได้ศึกษาด้วยตัวเองมาสักพัก ผมพบว่ามันมีเนื้อหาทางคณิตศาสตร์น่าสนใจ ที่เกี่ยวข้องกับ Functional Programming อยู่หลายอย่าง แต่ผมจะแตกออกมาหลักๆก็คือ <a href="https://en.wikipedia.org/wiki/Lambda_calculus">Lambda Calculus</a>, <a href="https://en.wikipedia.org/wiki/Abstract_algebra">Abstract Algebra</a>, <a href="https://en.wikipedia.org/wiki/Category_theory">Category Theory</a>, <a href="https://en.wikipedia.org/wiki/Type_theory">Type Theory</a> (อาจจะมี <a href="https://en.wikipedia.org/wiki/Homotopy_theory">Homotopy Theory</a> กับ <a href="https://en.wikipedia.org/wiki/Homotopy_type_theory">Homotopy Type Theory</a> ด้วยถ้าไหว แต่ขอดูอีกทีดีกว่า) แล้วก็ตัว <a href="https://en.wikipedia.org/wiki/Functional_programming">Concept ของ Functional Programming</a> เอง ซึ่งถ้าผมเข้าใจในเนื้อหามันได้ประมาณนึง และมีเวลา ไม่ขี้เกียจ ก็อยากจะเขียนสรุปทุกๆหัวข้อพวกนี้ไว้เท่าที่ตัวเองตามเนื้อหาของมันไหวเลยครับ :)</p><h3>Lambda Calculus ?</h3><p>เห็นคำว่า Calculus โดยสามัญสำนึกของเด็กไทย ที่ผ่านการศึกษาระดับมัธยมปลายเป็นขั้นต่ำมา ผมว่าหลายคนน่าจะนึกถึง Limit, Differentiate, Integral ถั่วงอก dx/dy อะไรแบบนี้แน่ๆเลยใช่ไหมล่ะ! ผมรู้นะ!</p><p>แต่จริงๆแล้วในหัวข้อทางคณิตศาสตร์เองก็มีส่วนที่ไม่ได้พูดถึงประเด็นข้างต้นที่กล่าวมาขนาดนั้น แต่ก็ใช้คำว่า Calculus เหมือนกัน หนึ่งในนั้นก็คือ Lambda Calculus ไงล่ะ</p><p>แล้ว Lambda Calculus จริงๆแล้วมันคืออะไรล่ะ ?</p><p>Lambda Calculus คือโมเดลทางคณิตศาสตร์รูปแบบหนึ่งที่พูดถึง 3 ส่วนนี้ครับ</p><ol><li>) Variable หรือ ตัวแปร</li><li>) Abstraction หรือ Lambda Abstraction ก็คือการเขียนให้อยู่ในรูปคล้ายๆกับฟังก์ชัน</li><li>) Application หรือ การประยุกต์ตัวแปร หรือ Expression เข้ากับ Abstraction</li></ol><p>นักคณิตศาสตร์ท่านหนึ่งที่ชื่อ <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwishrnOorWEAxWIxDgGHTR7DX4QFnoECCUQAQ&amp;url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FAlonzo_Church&amp;usg=AOvVaw3innsCiE3Ua7sZ7EXzPouh&amp;opi=89978449">Alonzo Church</a> (คนมักจะรู้จักท่านนี้ในฐานะ Supervisor ของบิดาแห่งคอมพิวเตอร์อย่าง <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjz_aHforWEAxUa8zgGHfe6Bj8QFnoECCwQAQ&amp;url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FAlan_Turing&amp;usg=AOvVaw0zl9L_kugoSJAGrPejvhD0&amp;opi=89978449">Alan Turing</a>) ได้คิดค้นหลักการนี้ขึ้นมา ซึ่งมีหัวใจสำคัญคือการคำนวณด้วยการแทนค่า Variable ลงใน Abstraction ผ่าน Application ซึ่งเราจะลงรายละเอียดคำเหล่านี้ในหัวข้อถัดไป</p><p>ที่ผมขึ้นชื่อบทความว่าเป็นพ่อทุกสถาบันแห่งการคำนวณ เพราะมันเคยมีประโยคที่พูดถึง Lambda Calculus ประมาณว่า</p><blockquote>ทุกอย่างที่คำนวณได้ สามารถเขียนรูปแบบการคำนวณให้อยู่ใน Form ของ Lambda Calculus ได้เสมอ หรือก็คือ ทุกอย่างที่คำนวณได้ สามารถคำนวณได้ด้วย Lambda Calculus ได้เสมอนั่นแหละ</blockquote><p>ซึ่งเราจะขยายความถึงการนำรูปแบบของ Lambda Calculus ไปใช้ในการคำนวณในหัวข้อต่างๆทางคณิตศาสตร์ได้อย่างไร ในบทความถัดๆไป</p><h3>Variable</h3><p>Variable หรือ ตัวแปร ในที่นี้เราพูดถึงตัวแปรปกติที่เราเข้าใจกันเลยอย่างเช่น X, Y หรือ ในหัวข้ออาจจะมีการพูดถึง True, False (Boolean) ซึ่งพวกนี้ก็นับว่าเป็น Variable ได้เช่นกัน เนื่องจากมีการแทนค่าตัวแปรเหล่านี้ได้ด้วย Expression หรืออยู่ในรูป Abstraction ซึ่งเราจะพูดถึงกันต่อไป</p><h3>Abstraction</h3><p>การเขียนในรูปแบบ Abstraction ในบริบทหัวข้อ Lamda Calculus จะมีรูปร่างประมาณนี้ครับ</p><p>λ&lt;Parameter 1&gt;.λ&lt;Parameter 2&gt;.&lt;ไล่ประมาณนี้ไปเรื่อยๆ&gt;.λ&lt;Parameter n&gt;.&lt;Return Expression&gt;</p><p>ยกตัวอย่างเช่น</p><ul><li>λx.x เทียบเท่ากับ f(x) = x</li><li>λx.λy.x (สามารถเขียนในรูปย่อได้ว่า λxy.x) เทียบเท่ากับ f(x)(y) = x (ไม่ใช่ f(x, y) = x เดี๋ยวจะลงรายละเอียดเพิ่มเติมในหัวข้อ Currying)</li></ul><p>ใช่ครับ การเขียน Lambda Abstraction มันจะมีลักษณะคล้ายๆกับการเขียนฟังก์ชันในหัวข้อเรื่อง<a href="https://en.wikipedia.org/wiki/Relation_(mathematics)">ความสัมพันธ์</a>​ และ<a href="https://en.wikipedia.org/wiki/Function_(mathematics)">ฟังก์ชัน</a>นั่นแหละครับ</p><h3>Application</h3><p>การนำตัวแปร หรือ Expression ไปประยุกต์ใช้กับ Abstraction (หรือ Function)</p><p>ยกตัวอย่างเช่น</p><ul><li>(λx.x 2) มีความหมายว่าให้เอาตัวแปร 2 (2 ใน Lambda Calculus ให้เรานับว่าเป็นตัวแปรตัวหนึ่ง เพราะ Lambda Calculus จะพูดถึงตัวแปร และ การดำเนินการเป็นหลักเท่านั้น) ไปแทนที่ตัวแปร x ใน Abstraction λx.x ก็จะได้ผลลัพธ์มาเป็น 2 (เพราะว่าเราเอา 2 ไปแทน x แล้วใน Abstraction มันรับ parameter เป็น x จากนั้นก็ return x ออกมาเลย เราแทน x เป็น 2 แปลว่า Abstraction ดังกล่าวก็ Return ค่าออกมาเป็น 2 นั่นเอง ผมอธิบายชวนงงไปไหมหว่า ?) อารมณ์ประมาณว่า f(x) = x เราแทน x = 2 ก็ได้ว่า f(2) = 2 ก็คือผลลัพธ์ของ f(2) ก็คือ 2 นั่นแหละ</li><li>(λx.λy.xy 2 3) =&gt; เอา 2 ไปแทนค่าใน x (แทนค่าตามลำดับ) ได้เป็น (λ2.λy.2y 3) =&gt; (λy.2y 3) เอา 3 ไปแทนค่า y ได้เป็น (λ3.23) =&gt; 23 (ให้มองว่าเราเอา 2 กับ 3 มาประกบกันเฉยๆ ไม่ใช่ตัวเลข 23 ที่อ่านว่า ยี่สิบสาม นะ)</li></ul><p>อธิบายให้เข้าใจ (หรือเปล่า ?) ก็คือ Application จะประกอบไปด้วย Expression ฝั่งซ้าย ซึ่งจะเป็น Abstraction หรือไม่ก็ Variable ที่แทนค่าเป็น Abstraction ได้ และ Expression ฝั่งขวา (Expression แต่ละฝั่งถูกคั่นผ่าน Whitespace นะ) เราก็แค่เอา Expression ทางขวา ไปแทนเป็นค่าใน Parameter ใน Abstraction แล้วก็เอาไปแทนตัวแปรเดียวกันใน Return Expression ของตัว Abstraction ก็จะได้ผลลัพธ์ของ Abstraction นั้นออกมาเป็น Return Expression ที่ได้รับการแทนค่าเรียบร้อยแล้ว เช่น</p><h3>Currying (แถม)</h3><p>เมื่อกี้เราติดค้างกันไปว่าทำไม λx.λy.x เวลามองเป็นฟังก์ชันทางคณิตศาสตร์ว่าเป็น f(x)(y) = x (อ่านว่า ฟังก์ชันที่รับพารามิเตอร์เป็น x แล้วได้ผลลัพธ์เป็นฟังก์ชันที่รับพารามิเตอร์เป็น y แล้วได้ผลลัพธ์เป็น x) แทนที่จะเป็น f(x, y) = x (อ่านว่า ฟังก์ชันที่รับพารามิเตอร์สองตัว เป็น x, y แล้วได้ผลลัพธ์เป็น x)</p><p>คอนเซปต์ของการสร้างฟังก์ชันซ้อนกันโดยแต่ละฟังก์ชันจะรับพารามิเตอร์แค่ตัวเดียว เราเรียกมันว่า <a href="https://en.wikipedia.org/wiki/Currying">Currying</a></p><p>สิ่งที่แตกต่างกันระหว่าง Currying Function กับ ฟังก์ชันแบบทั่วไปคืออะไร ?</p><p>สมมติว่าเรามีฟังก์ชัน f(x)(y) = x + y ถ้าหากเราแทนค่า x เป็น 5 ฟังก์ชันจะอยู่ในรูป f(5)(y) = 5 + yใช่ไหมครับ</p><p>เราสามารถแทนค่า f(5) ในตัวแปรตัวอื่นได้ครับ เช่น plus5 = f(5) ก็จะได้เป็นว่า</p><p>f(5)(y) = plus5(y) = 5 + y เราสามารถทำแบบนี้กับ Currying Function แต่เราไม่สามารถทำแบบนี้กับฟังก์ชันอย่าง f(x, y) = x + y (ถ้าเราแทนค่า x เป็น 5 ในฟังก์ชัน ฟังก์ชันนี้ก็จะเป็นแค่ฟังก์ชันที่ยังไม่สามารถหาผลลัพธ์ได้อย่างสมบูรณ์)</p><p>และการมองฟังก์ชันเป็น Currying Function ก็จะถูกนำมาใช้ในการตีความ Lambda Abstraction อย่างเช่น</p><p>λx.λy.x ก็จะมองว่ามันเป็น Lamda Abstraction ที่รับ x แล้ว return เป็น Lambda Abstraction ที่รับ y แล้ว return เป็น x</p><h3>เปรียบเทียบ Lambda Calculus Form กับ Javascript Syntax</h3><p>หัวข้อนี้เป็นส่วนที่ผมขออนุญาตเพิ่มเติมจากเวอร์ชันที่ Publish ไปก่อนแล้ว เพราะเนื้อหาหลายส่วนของบทความนี้ผมอ้างอิงความเข้าใจมาจากวิดีโอ <a href="https://www.youtube.com/watch?v=3VQ382QG-y4">Lambda Calculus — Fundamentals of Lambda Calculus &amp; Functional Programming in JavaScript — YouTube</a></p><p>แล้วส่วนตัวผมรู้สึกชอบที่คุณ <a href="https://www.youtube.com/@glebec">Gabriel Lebec</a> (ผู้สอนในวิดิโอ) เปรียบเทียบ Lambda Abstraction กับ Javascript’s Arrow Function แล้วก็เปรียบเทียบ Application กับการใช้งาน Function ใน Javascript ทำให้ผมเข้าใจการทำงานของ Abstraction กับ Application มากขึ้น เลยอาจจะเอาตารางเปรียบเทียบในวิดิโอมาแปะในบทความให้ผู้อ่านได้ทำความเข้าใจกันด้วยครับ</p><h4>Variable</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Yd8aPG48A6-NmfJuiqfE_Q.jpeg" /><figcaption>เทียบ Variable ระหว่าง Lambda Calculus Form (ทางซ้าย ตัวอักษรสีฟ้า) กับ JavaScript Syntax (ทางขวา ตัวอักษรสีแดง)</figcaption></figure><h4>Application</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9wLMMnmLzIrH6rWVeftDog.jpeg" /><figcaption>เทียบ Application ระหว่าง Lambda Calculus Form (ทางซ้าย ตัวอักษรสีฟ้า) กับ JavaScript Syntax (ทางขวา ตัวอักษรสีแดง)</figcaption></figure><h4>Abstraction</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ad4wxXyZ7t18-nisn-OyWg.jpeg" /><figcaption>เทียบ Abstraction ระหว่าง Lambda Calculus Form (ทางซ้าย ตัวอักษรสีฟ้า) กับ JavaScript Syntax (ทางขวา ตัวอักษรสีแดง)</figcaption></figure><h3>สรุป</h3><p>หลักๆแล้ว Lambda Calculus จะพูดถึง Expression ที่อยู่ในรูป Variable, Lambda Abstraction และ Application ตามที่ได้พูดถึงไป ใน Blog ถัดไปเราจะพูดถึงเรื่องของการดำเนินการภายใน Lambda Calculus อย่างลงรายละเอียดให้เห็นจริงๆ ว่าเราจะใช้องค์ประกอบที่กล่าวมาข้างต้น ในการคำนวณออกมาเป็นผลลัพธ์ สำหรับโจทย์การคำนวณต่างๆได้อย่างไร เนื่องจากบทความนี้เราต้องการแค่จะอธิบายถึงนิยาม และ รูปแบบพื้นฐานของ Lambda Calculus ก่อน ขอบคุณครับ</p><h3>แหล่งอ้างอิง (References)</h3><ul><li><a href="https://kitty.in.th/index.php/articles/lambda-calculus-and-functional-languages/">แนะนำ Lambda Calculus และ Functional Languages | kitty.in.th</a></li><li><a href="https://www.youtube.com/watch?v=3VQ382QG-y4">Lambda Calculus — Fundamentals of Lambda Calculus &amp; Functional Programming in JavaScript (youtube.com)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14412c850bf1" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>