我得到了以下練習(在幾個連接起來的表格中的一個,可以漂亮地列印一個表格并在其中進行選擇):
寫一個函式select:: Field → Field → Table → Table,給定一個列名和一個欄位值,只從表中選擇那些在給定列中有給定欄位值的行。如果給定的列在表中不存在,那么該表應該被原封不動地回傳。(提示:使用函式(!!)、elemIndex、filter 和 maybe。)
最后的解決方案是:
select :: Field -> Field -> Table -> Tableselect column value table@(header:rows) =
let i = fromMaybe (-1) (elemIndex column header)
in if i ==(-1) then table
else header : filter (
-> r !i == value) rows
雖然它的功能似乎是完全正確的--它可以作業--但有人告訴我,像這樣的if-then-else結構是 "糟糕的形式",應該避免使用防護措施(正如我使用fromMaybe的模式匹配一樣)。
我將如何通過模式匹配/守護將其改變為 "更好 "的風格?
uj5u.com熱心網友回復:
當我看到你的代碼時,一個簡單的改進是,使用fromMaybe將Nothing轉換為-1,然后簡單地對該值是否為-1進行檢查(無論是用if還是用guards并不重要),似乎毫無意義。為什么不在一開始就對Nothing進行檢查呢?
我猜你可能被其他語言中的類似函式引導到這個方向,如果一個索引沒有被找到,那么-1將作為一個人工值(有時被稱為 "哨兵值")被回傳,以表示 "元素沒有被找到" - 但是在Haskell中,Nothing可以更好地傳達這個意思。
進一步的Nothing可以被模式匹配,所以與其使用if或guards,你可以使用case陳述句。這就把你的函式變成了:
select :: Field -> Field -> Table -> Tableselect column value table@(header:rows) =
case elemIndex列頭 of
Nothing -> table
Just i -> header : filter (
-> r !i == value) rows
在我看來,這比你原來的要好得多。
我仍然覺得它可以進一步改進--特別是(!!)在習慣的Haskell代碼中很少使用,因為如果索引超出了邊界,它有崩潰的風險。與其他語言的陣列索引操作相比,它的效率也很低(因為Haskell的串列是鏈接串列,而不是陣列,要想得到第100個元素,就必須運行之前的99個元素,而不是能夠直接進行 "隨機訪問")。然而,考慮到你在這里的作業,我不知道你如何能真正避免這種情況。
uj5u.com熱心網友回復:
替換
let i = fromMaybe (-1) (elemIndex column header)
in if i ==(-1) then ... else ...
與
case elemIndex columns header of
Nothing -> ... --沒有找到索引。
Just i -> ... --找到了i的索引。
你的原始代碼患有 "布爾盲癥":你已經有一個有用的Maybe Int型別的值,它告訴你:
- 如果沒有索引,那么你就會發現,在你的計算機上有一個 "布爾盲"。
- 如果沒有索引(
Nothing) - 如果有一個索引,和它是什么(
Just i)
最后強調的部分很重要! 在你的代碼中,你努力作業以失去這些資訊,將所有的東西簡化為一個布林值,只告訴你:
- 如果沒有索引,那么就會有
- 如果沒有索引(
True) - 如果有一個索引,而沒有其他東西(
False) 。
除非你真的需要,否則不要使用布爾運算。許多語言必須使用if someBooleanCondition來進行條件性分支。Haskell不必如此:我們有case和模式匹配,它結合了分支和從每個案例中提取資訊(上面的i)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/325728.html
標籤:
