blog นี้ผมจะชวนมารู้จักกับ Curry และ pipe() ใน Functional programming in Typescript
ผมคาดหวังว่าหลังจากอ่านจบเพื่อนๆน่าจะนำเอา Curry ไปประยุคใช้กับ pipe function ใน Typescript ได้
โดยจะสร้าง Curried function เอง หรือสร้างโดยใช้ helper function จาก lib ผมจะพาทำทั้งหมดครับ
Curried function
เรามี function ที่รับ parameters หลายๆตัว แล้วเราแปลง function นั้นให้กลายเป็น function ที่รับ parameter แค่ 1 ตัว แล้ว return function ซึ่ง function นี้จะรับ parameters ตัวที่เหลือ
ซึ่ง function ตัวที่ return นั้นจะรับ parameters ตัวที่เหลือทั้งหมดเลยก็ได้ หรือจะ รับ parameter แค่ตัวเดียวแล้ว return function ที่รับ parameter อีกทีนึงก็ได้
พอทำแบบนี้ Curry ก็จะเป็น Higher Order Function ไปด้วย
ส่วน Higher Order Function คืออะไร ผมเคยทำคลิปไว้ อาจจะยาวหน่อยไปตามดูกันได้ CodeSook Youtube: Higher Order Function
ทำไมเราต้องใช้ Curry ด้วยละ
Curry จะช่วยให้เรา
Function composition เอา function หลายตัวมาใช้งานต่อกันได้ง่ายขึ้น ใน blog นี้ผมจะแสดงให้เห็นตรงจุดนี้แหละ โดยจะใช้ร่วมกับ pipe()
Partial Application สร้าง function ที่รับ parameter ไปก่อนตัวนึง แล้วเราจะได้ function กลับมา function นั้นจะต้องรับ parameter ที่เหลือ
ทำให้เราสามารถเอา function ที่ต้องการ parameter บางตัวร่วมกัน เอาไปใช้งานได้สะดวกมากขึ้น
Point-Free Style ใช้งาน function โดยที่ไม่ต้องใส่ parameter ทำให้ code กระชับมากขึ้น
return cart.reduce((total,item)=> total + (item.price * item.quantity),0)
14
}
โค้ดเริ่มต้นในตัวอย่างด้านบน เรามีสินค้าในตะกร้า แล้วมี function calculatePriceInCart ที่เราไว้รวมราคาสินค้า
เรามาสร้าง functions คำนวณการลดราคา คำนวณ tax
11 collapsed lines
1
type
type Item ={
price:number;
quantity:number;
}
Item={
2
price: number
price:number
3
quantity: number
quantity:number
4
}
5
6
const
const shoppingCart:{
price:number;
quantity:number;
}[]
shoppingCart= [
7
{
price: number
price:29.99,
quantity: number
quantity:2},// Two t-shirts
8
{
price: number
price:49.99,
quantity: number
quantity:1},// One pair of jeans
9
{
price: number
price:9.99,
quantity: number
quantity:3}// Three pairs of socks
10
]
11
12
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
13
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
ทีนี้เราก็เอามาแปลงให้เป็น Curried function
จะได้แบบนี้
11 collapsed lines
1
type
type Item ={
price:number;
quantity:number;
}
Item={
2
price: number
price:number
3
quantity: number
quantity:number
4
}
5
6
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
7
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
8
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
9
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
10
]
11
12
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
13
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
จะเห็นว่าไม่ยากเลย
แต่ตอนเรียกใช้งานเราต้องใส่วงเล็บต่อๆกัน เราจะไม่คุ้ยเคยหน้าตาการเรียกใช้ function แบบนี้กันสักเท่าไรใช่ไหมครับ
เดี๋ยวด้านล่างผมจะพาแก้ปัญหานี้ แต่ขอไปเรื่อง pipe ก่อน
pipe function
อย่างที่บอกไปว่าประโยชน์อย่างหนึ่งของ Curried function คือทำให้เราเอา function มาใช้งานต่อๆ(compose)กันได้ง่ายขึ้น
และส่วนตัวผมคิดว่าการใช้ pipe() เป็นการ compose function แล้วอ่านง่ายที่สุด
pipe() ใน Effect จะเริ่มต้นด้วยการรับ value เข้ามา
26 collapsed lines
1
import{
functionpipe<A>(a: A):A(+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
จากนั้นก็จะต้องตามด้วย function ซึ่ง parameter ใน function นี้จะมีได้แค่ตัวเดียว
นั่นคือทำไมเราต้องทำ function ของเราให้เป็น curried function
pipe จะเอา value ที่ได้ก่อนหน้ามาใส่ให้เรา เป็น argument ใน function ถัดไป
และ function นั้น จะต้อง return ด้วยนะ
แล้ว pipe ก็จะเอา return value ที่ได้จาก function ส่งต่อไปให้กับ function ถัดไป ถัดไป ถัดไป เรื่อยๆ
ถ้าไม่มี function ถัดไป ก็จะเอา return value ไปเก็บในตัวแปร const totalPrice = pipe() เป็นการจบการทำงานของ pipe()
มาดูโค้ดของเรา
25 collapsed lines
1
import{
functionpipe<A>(a: A):A(+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
pipe<Item[],number>(a: Item[], ab: (a: Item[])=> number): number (+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
จากโค้ดด้านบนเราเริ่มต้นด้วยการใส่ valueshoppingCart ไปก่อน
แล้วตามด้วย function ที่รับ parameter 1 ตัว ซึ่ง value ของ parameter นี้ก็จะเป็นค่า value ของ shoppingCart น่ะแหละ
ในโค้ดด้านบนเราสร้าง function ที่รับ parameter ตัวเดียวด้วย arrow function
ผมจะเอา function คำนวน discount กับคำนวณ tax มาใช้ด้วย แบบนี้
25 collapsed lines
1
import{
functionpipe<A>(a: A):A(+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
เราจะเอาไปทำเป็น Curried function ก็ให้สลับตำแหน่องของ parameters แบบนี้
มาดู code กัน
15 collapsed lines
1
type
type Item ={
price:number;
quantity:number;
}
Item={
2
price: number
price:number
3
quantity: number
quantity:number
4
}
5
6
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
7
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
8
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
9
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
10
]
11
12
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
13
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
reduce((
total: number
total,
item: Item
item)=>
total: number
total+ (
item: Item
item.
price: number
price*
item: Item
item.
quantity: number
quantity),0)
14
}
15
16
// function applyDiscount(cartPrice: number, discountPercent: number): number {
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
ถ้าเราจะเอาตัวแปรมารับค่าจาก function แล้วค่อยใชัตัวแปรนั้นในอีก function นึงก็ไม่ได้ผิดนะครับ ส่วนตัวผมมองว่าใช้ pipe() มันอ่านง่ายกว่า เราไม่ต้องคอยจำตัวแปรในหัวเวลาอ่านโค้ด
ยิ่งถ้าเราตั้งชื่อ function ให้มันสื่อถึงงานที่มันทำ เราไม่ต้องไปสนใจเลยว่า function มันจะคำนวณยังไง เราก็ยังสามารถเข้าใจภาพรวมของโปรแกรมได้ง่ายๆเลย
ทีนี้เราก็ใส่ applyTax เข้าไปด้วย
17 collapsed lines
1
import{
functionpipe<A>(a: A):A(+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe}from"effect"
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
pipe<Item[],number,number,number,number>(a: Item[], ab: (a: Item[])=> number, bc: (b:number)=> number, cd: (c:number)=> number, de: (d:number)=> number): number (+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
ด้านบนเป็นตัวอย่างการเขียน Function Overloading
ทำให้เรามี function ที่มีชื่อเดียวกัน แต่ parameters และ return type ไม่เหมือนกันได้
แต่พอจะเขียนการทำงานจริงๆ มันจะซับซ้อนตรงนี้แหละ
การใช้ Function Overloading ผมจะไม่ลงลึกมากนะครับ
แค่ยกตัวอย่างมาเพื่อให้เพื่อนๆเห็นว่าสามารถแก้ปัญหาแบบนี้ได้ด้วย
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
เรามี function อยู่ก่อนแล้ว ผมใช้ชื่อว่า _applyDiscount() นะครับ ตามโค้ดด้านบน
เราจะเอามาใส่ใน dual() นี่แหละ
เราจะต้องบอก dual() ว่า function ของเรามี parameters กี่ตัว ในที่นี้คือ 2 ครับ แล้วตามด้วย function ของเรา
ส่วน type ของ function นี้ก็คือส่วนนี้
ในส่วนของ type เราจะต้องเอา type ของ function ที่มี parameters มากที่สุดไว้เป็นตัวสุดท้ายนะครับ ในที่นี้คือ typeof _applyDiscount
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
It's important to note that functions passed to pipe must have a single
argument because they are only called with a single argument.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import{ pipe, Array }from"effect"
pipe(as, Array.map(f), Array.filter(g))
Example (Chaining Arithmetic Operations)
import{ pipe }from"effect"
// Define simple arithmetic operations
constincrement=(x:number)=> x +1
constdouble=(x:number)=> x *2
constsubtractTen=(x:number)=> x -10
// Sequentially apply these operations using `pipe`
const result =pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2
@since ― 2.0.0
pipe,
import Function
Function}from"effect"
16 collapsed lines
2
3
type
type Item ={
price:number;
quantity:number;
}
Item={
4
price: number
price:number
5
quantity: number
quantity:number
6
}
7
8
const
const shoppingCart: Item[]
shoppingCart:
type Item ={
price:number;
quantity:number;
}
Item[] = [
9
{
price: number
price:10,
quantity: number
quantity:2},// Two t-shirts
10
{
price: number
price:20,
quantity: number
quantity:1},// One pair of jeans
11
{
price: number
price:3,
quantity: number
quantity:3}// Three pairs of socks
12
]
13
14
function
functioncalculatePriceInCart(cart: Item[]):number
calculatePriceInCart(
cart: Item[]
cart:
type Item ={
price:number;
quantity:number;
}
Item[]):number{
15
return
cart: Item[]
cart.
Array<Item>.reduce<number>(callbackfn: (previousValue:number,currentValue: Item,currentIndex:number,array: Item[])=> number, initialValue: number): number (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@param ― callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
@param ― initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
Creates a function that can be used in a data-last (aka pipeable) or
data-first style.
The first parameter to dual is either the arity of the uncurried function
or a predicate that determines if the function is being used in a data-first
or data-last style.
Using the arity is the most common use case, but there are some cases where
you may want to use a predicate. For example, if you have a function that
takes an optional argument, you can use a predicate to determine if the
function is being used in a data-first or data-last style.
You can pass either the arity of the uncurried function or a predicate
which determines if the function is being used in a data-first or
data-last style.
Example (Using arity to determine data-first or data-last style)
import{ dual, pipe }from"effect/Function"
const sum = dual<
(that:number)=>(self:number)=> number,
(self:number,that:number)=> number
>(2,(self,that)=> self + that)
console.log(sum(2,3)) // 5
console.log(pipe(2,sum(3))) // 5
Example (Using call signatures to define the overloads)
pipe<Item[],number,number,number,number>(a: Item[], ab: (a: Item[])=> number, bc: (b:number)=> number, cd: (c:number)=> number, de: (d:number)=> number): number (+19 overloads)
Pipes the value of an expression into a pipeline of functions.
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import{ pipe }from"effect"
const result =pipe(input, func1, func2,..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
Returns a copy of a section of an array.
For both start and end, a negative index can be used to indicate an offset from the end of the array.
For example, -2 refers to the second to last element of the array.
@param ― start The beginning index of the specified portion of the array.
If start is undefined, then the slice begins at index 0.
@param ― end The end index of the specified portion of the array. This is exclusive of the element at the index 'end'.
If end is undefined, then the slice extends to the end of the array.
slice(0,
arity: FPArity
The arity of the function
@param ― arity - The arity of the function
arity).
Array<unknown>.reverse(): unknown[]
Reverses the elements in an array in place.
This method mutates the array and returns a reference to the same array.