3 回答

TA貢獻(xiàn)1821條經(jīng)驗(yàn) 獲得超5個(gè)贊
第二種方法更為慣用。事實(shí)上,第二種方法在函數(shù)式編程中有一個(gè)名字。將共享靜態(tài)值作為輸入(又稱為環(huán)境)的函數(shù)稱為reader。
// Reader e a = e -> a
// ask : Reader e e
const ask = x => x;
// pure : a -> Reader e a
const pure = x => _ => x;
// bind : Reader e a -> (a -> Reader e b) -> Reader e b
const bind = f => g => x => g(f(x))(x);
// reader : Generator (Reader e a) -> Reader e a
const reader = gen => (function next(data) {
? ? const { value, done } = gen.next(data);
? ? return done ? value : bind(value)(next);
}(undefined));
// Environment = { foo : Number, bar : Number }
// function1 : Reader Environment Number
const function1 = reader(function* () {
? ? const { foo, bar } = yield ask;
? ? return pure(foo + bar);
}());
// function2 : Reader Environment Number
const function2 = reader(function* () {
? ? const { foo, bar } = yield ask;
? ? return pure(foo * bar);
}());
// myFunction : Reader Environment (Array Number)
const myFunction = reader(function* () {
? ? const res1 = yield function1;
? ? const res2 = yield function2;
? ? return pure([res1, res2]);
}());
// results : Array Number
const results = myFunction({ foo: 10, bar: 20 });
console.log(results);
在上面的示例中,我們使用一元表示法定義function1
、function2
、 和。myFunction
請(qǐng)注意,myFunction
沒有明確將環(huán)境作為輸入。它也沒有顯式地將環(huán)境傳遞給function1
和function2
。所有這些“管道”都是由pure
和bind
函數(shù)處理的。我們使用一元?jiǎng)幼髟L問一元上下文中的環(huán)境ask
。
Reader
然而,當(dāng)我們使用 monad 轉(zhuǎn)換器將 monad 與其他 monad結(jié)合起來(lái)時(shí),真正的優(yōu)勢(shì)就會(huì)出現(xiàn)ReaderT
。
編輯:如果您不想,則不必使用單子表示法。您可以按如下方式定義function1
、function2
、 和。myFunction
// Reader e a = e -> a
// Environment = { foo : Number, bar : Number }
// function1 : Reader Environment Number
const function1 = ({ foo, bar }) => foo + bar;
// function2 : Reader Environment Number
const function2 = ({ foo, bar }) => foo * bar;
// myFunction : Reader Environment (Array Number)
const myFunction = env => {
? ? const res1 = function1(env);
? ? const res2 = function2(env);
? ? return [res1, res2];
};
// results : Array Number
const results = myFunction({ foo: 10, bar: 20 });
console.log(results);
缺點(diǎn)是現(xiàn)在您明確地將環(huán)境作為輸入并將環(huán)境傳遞給子計(jì)算。不過,這可能是可以接受的。
編輯:這是另一種編寫方法,不使用一元符號(hào),但仍然使用ask、pure和bind。
// Reader e a = e -> a
// ask : Reader e e
const ask = x => x;
// pure : a -> Reader e a
const pure = x => _ => x;
// bind : Reader e a -> (a -> Reader e b) -> Reader e b
const bind = f => g => x => g(f(x))(x);
// Environment = { foo : Number, bar : Number }
// function1 : Reader Environment Number
const function1 = bind(ask)(({ foo, bar }) => pure(foo + bar));
// function2 : Reader Environment Number
const function2 = bind(ask)(({ foo, bar }) => pure(foo * bar));
// myFunction : Reader Environment (Array Number)
const myFunction =
? ? bind(function1)(res1 =>
? ? ? ? bind(function2)(res2 =>
? ? ? ? ? ? pure([res1, res2])));
// results : Array Number
const results = myFunction({ foo: 10, bar: 20 });
console.log(results);
請(qǐng)注意,使用生成器的一元表示法只是上述代碼的語(yǔ)法糖。

TA貢獻(xiàn)1826條經(jīng)驗(yàn) 獲得超6個(gè)贊
您的兩種方法都是正確的。這里的問題是該代碼與應(yīng)用程序相關(guān)的上下文,這些函數(shù)是否與它們定義/使用的范圍相關(guān)?
考慮這個(gè)例子。
const Calculator = class {
complexOperation({foo, bar}) {
const results = []
const res1 = this.sum({foo, bar});
const res2 = this.dot({foo, bar});
results.push(res1, res2);
return results;
}
sum({foo, bar}) {
return foo + bar;
}
dot({foo, bar}){
return foo * bar;
}
};
var calc = new Calculator();
calc.complexOperation({foo: 2, bar: 3})
在這個(gè)例子中,我們可以看到功能級(jí)抽象是如何與意圖相關(guān)的。
永遠(yuǎn)記住牢記“降職規(guī)則”。
現(xiàn)在讓我們改變應(yīng)用意圖?,F(xiàn)在我們正在向法律機(jī)構(gòu)申請(qǐng),我們必須進(jìn)行復(fù)雜的操作來(lái)申請(qǐng)一些稅收。
現(xiàn)在 sum 和點(diǎn)不應(yīng)該成為類的一部分,因?yàn)橹粫?huì)在復(fù)雜操作中使用,新開發(fā)人員不關(guān)心 function1(我將其重命名為 sum)做什么,他們不必閱讀它,所以我們可以改變抽象級(jí)別。事實(shí)上,您將以包含一些步驟的方法結(jié)束。
在其他語(yǔ)言中,例如c#,您可以在使用后定義函數(shù),但在javascript中則不能,因此您不能在JS中的本地函數(shù)中應(yīng)用Stepdown規(guī)則。有些人顛倒了Stepdown Rule,將所有局部函數(shù)都定義在函數(shù)start中,所以他們的眼睛就跳到最后一個(gè)局部函數(shù)結(jié)束括號(hào)并開始閱讀。
const BusinessTaxes = class {
complexOperation({foo, bar}) {
const addTax = () => {
return foo + bar;
}
const dotTax = () => {
return foo * bar;
}
// Jump your eyes here
const results = []
const res1 = addTax({foo, bar});
const res2 = dotTax({foo, bar});
results.push(res1, res2);
return results;
};
};
var businessTax= new BusinessTaxes();
businessTaxes.complexOperation({foo: 2, bar: 3})
總之,將您的代碼組織成相同的抽象級(jí)別,保持其結(jié)構(gòu)化并與您的決策保持一致,您的代碼將具有可讀性和可維護(hù)性。

TA貢獻(xiàn)1817條經(jīng)驗(yàn) 獲得超6個(gè)贊
當(dāng)開發(fā)人員專注于明確自己的意圖時(shí),可讀性往往是一個(gè)副產(chǎn)品。
下一個(gè)開發(fā)人員(或未來(lái)的您)會(huì)理解您的意圖嗎?
恕我直言,這是您應(yīng)該回答的唯一問題嗎,因?yàn)樗P(guān)注的是比“這看起來(lái)不錯(cuò)嗎?”更具體的問題。
從這個(gè)角度來(lái)看,兩個(gè)版本都做到了這一點(diǎn)。
除了兩者:
可以用更好的名字
可以使用新的語(yǔ)法來(lái)使其更容易被眼睛看到
const sumproduct_pair = ({a, b}) => {
const sum = () => a + b;
const product = () => a * b;
return [sum(), product()];
};
或者
const sum = ({a, b}) => a + b;
const product = ({a, b}) => a * b;
const sumproduct_pair = ({a, b}) => [sum({a, b}), product({a, b})];
然而,這兩個(gè)版本都可以改進(jìn),但還是 YMMV:
在第一個(gè)版本中, 和sum都不product需要存在。它們顯然不適合重復(fù)使用,而且非常簡(jiǎn)單,可以簡(jiǎn)化為最簡(jiǎn)單的表達(dá):
const sumproduct_pair = ({a, b}) => [a+b, a*b];
在第二個(gè)版本中,如果您打算重用sum并重product用,請(qǐng)考慮“針對(duì)接口而不是實(shí)現(xiàn)進(jìn)行設(shè)計(jì)”。
該函數(shù)sumproduct_pair需要一個(gè)具有屬性的對(duì)象a,b但這并不意味著所有其他函數(shù)都需要具有相同的接口:
const sum = (a, b) => a + b;
const product = (a, b) => a * b;
const sumproduct_pair = ({a, b}) => [sum(a, b), product(a, b)];
雖然這看起來(lái)像是一個(gè)微不足道的更改,但它刪除了一些不必要的大括號(hào)(如果您想通過減少編寫來(lái)提高可讀性),最重要的是允許 和 處理sum未知product數(shù)量的數(shù)字:
const sum = (...xs) => xs.reduce((ret, x) => ret + x, 0);
const product = (...xs) => xs.reduce((ret, x) => ret * x, 1);
sum(1, 2, 3); //=> 6
sum(1, 2, 3, 4); //=> 10
product(1, 2, 3); //=> 6
product(1, 2, 3, 4); //=> 24
添加回答
舉報(bào)