“使用帶有兩個引數的以下函式:
nth :: (a,a,a,a,a) -> Int -> a
其中 Int 值應回傳五元素元組的第 Int 個值。”我試過:
nth (a,b,c,d,e) x = (a,b,c,d,e) !! x
但是 GHC 給了我一個錯誤資訊:
file.hs:11:21: error:
* Couldn't match expected type `[a1]'
with actual type `(a, b, c, d, e)'
* In the first argument of `(!!)', namely `(a, b, c, d, e)'
In the expression: (a, b, c, d, e) !! x
In an equation for `nth':
nth (a, b, c, d, e) x = (a, b, c, d, e) !! x
* Relevant bindings include
e :: e (bound at file.hs:11:14)
d :: d (bound at file.hs:11:12)
c :: c (bound at file.hs:11:10)
b :: b (bound at file.hs:11:8)
a :: a (bound at file.hs:11:6)
nth :: (a, b, c, d, e) -> Int -> a1
(bound at file.hs:11:1)
我該怎么辦?我應該如何寫這個方程的元組部分?提前感謝您的回答!
uj5u.com熱心網友回復:
您不能使用,(!!) :: [a] -> Int -> a因為正如簽名所說,它適用于串列,而不是元組。您可以使用模式匹配并將其實作為:
nth :: (a, a, a, a, a) -> Int -> a
nth (a, _, _, _, _) 0 = a
nth (_, b, _, _, _) 1 = b
nth (_, _, c, _, _) 2 = c
nth (_, _, _, d, _) 3 = d
nth (_, _, _, _, e) 4 = e
已經有其中一個三元組被定義為提案(a, (b, c)),使得其因而其中一個遞回結構?元組被定義為2元組具有n-1個元組作為第二項。但情況并非如此(目前)。
uj5u.com熱心網友回復:
您可以通過將元組的模式匹配與 on 的匹配分開來避免現有模式匹配解決方案中的一些重復n:
nth :: (a, a, a, a, a) -> Int -> a
nth (a, b, c, d, e) n = case n of
0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
您還應該考慮當 n 不在范圍內時您希望發生什么[0, 4]。正如所寫的那樣,您將在運行時得到一個非窮盡的模式錯誤。回傳 aMaybe a或采用更受約束的型別作為輸入會更誠實,例如
data QuintupleIndex = Zero | One | Two | Three | Four
uj5u.com熱心網友回復:
(轉自我自己的評論)
實際上,其他答案中沒有提到一個簡單的解決方法:您只需要更改兩個符號:
nth :: (a, a, a, a, a) -> Int -> a
nth (a,b,c,d,e) x = [a,b,c,d,e] !! x
-- or alternatively
nth (a,b,c,d,e) = ([a,b,c,d,e] !!)
仍然需要進行模式匹配來找到第 n 個元素,但現在在!!.
這是有效的,因為 list 是同構的,這意味著它的所有元素都是相同的型別。在 的左側nth,您有模式(a,b,c,d,e),因此型別推斷給出a :: a, b :: b, ...了錯誤訊息中指示的最通用的約束。但是,一旦[a,b,c,d,e]在右側看到,它就會為型別推斷提供一個線索,即所有a, b, c, d,e都是同一型別!所以型別推斷現在可以確定型別檢查(a,b,c,d,e) :: (a,a,a,a,a)。
在 Haskell 中,元組并不意味著Int像串列一樣索引的容器型別(與 Python 和其他一些語言中的元組不同),而是更像是每個欄位都有特定含義的結構(認為它就像struct在 C 中一樣),如果您確實希望對其進行有效索引,則需要欄位選擇器而不是自然數:
data Five a = Five { _1 :: a, _2 :: a, _3 :: a, _4 :: a, _5 :: a }
現在您可以使用 訪問欄位_x,但型別nth將為:
nth :: Five a -> (Five a -> a) -> a
nth v f = f v
-- or pointfreely:
nth = flip id
(另一個好處是你有一個完整的函式,而不是一個可能會失敗模式匹配并引發例外的函式)
請注意,欄位選擇器是函式而不是自然數 - 如果您正在處理串列索引,那么詢問“下一個元素是什么?”是有意義的,但在涉及結構時則不然。
uj5u.com熱心網友回復:
該(!!)功能僅適用于串列。
對于元組,至少那些超??過 2 個元素的元組,訪問元素的唯一方法是通過直接模式匹配:
nth :: (a,a,a,a,a) -> Int -> a
nth (a, _, _, _, _) 0 = a
nth (_, a, _, _, _) 1 = a
nth (_, _, a, _, _) 2 = a
nth (_, _, _, a, _) 3 = a
nth (_, _, _, _, a) 4 = a
(注意_s,它的意思是“我不在乎這個值是什么”。你可以給他們一個名字 - 例如(a, b, c, d, e)在每一行上匹配,回傳值a在第一行,b第二行等等。但僅命名您關心的值會減少視覺“噪音”。)
另請注意,如果整數引數是 0-4 以外的任何值,則此函式將因“非窮盡模式”錯誤而崩潰。但是(!!)在 5 個元素的串列上使用也有類似的缺陷。您可以輕松地將默認情況添加到末尾,盡管在使用完全泛型型別時這并不容易,a因為沒有任何值可以作為呼叫函式的任何型別的回傳值!
uj5u.com熱心網友回復:
使用警衛的簡單解決方案如下:
nth :: (a,a,a,a,a) -> Int -> a
nth (a, b, c, d, e) i
| i == 0 = a
| i == 1 = b
| i == 2 = c
| i == 3 = d
| otherwise = e
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316830.html
下一篇:值在Haskell中被丟棄
