[英]Haskell : understanding “No instance for” error messages in ghci
問題1
嗨,如果我在WinGHCi中故意執行以下錯誤代碼:
3 4
然后我得到的錯誤信息是
<interactive>:1:1:
No instance for (Num (a0 -> t0))
arising from the literal `3'
Possible fix: add an instance declaration for (Num (a0 -> t0))
In the expression: 3
In the expression: 3 4
In an equation for `it': it = 3 4
No instance for (Num (a0 -> t0))
到底是什么意思?
問題2
為什么下面的代碼:
(+) 2 3 4
<interactive>:1:7:
No instance for (Num (a0 -> t0))
arising from the literal `3'
Possible fix: add an instance declaration for (Num (a0 -> t0))
In the second argument of `(+)', namely `3'
In the expression: (+) 2 3 4
In an equation for `it': it = (+) 2 3 4
與第二段代碼產生的錯誤略有不同:
2+3 4
<interactive>:1:3:
No instance for (Num (a1 -> a0))
arising from the literal `3'
Possible fix: add an instance declaration for (Num (a1 -> a0))
In the expression: 3
In the second argument of `(+)', namely `3 4'
In the expression: 2 + 3 4
即在第一段代碼中No instance for (Num (a0 -> t0))
,而在第二段代碼中我們No instance for (Num (a1 -> a0))
。
[回應ehird]
(問題從答案評論移到):
1)我理解后兩個表達式是不同的,但是您是在說我不應該理解為什么解釋器為前者選擇(Num (a0 -> t0))
並為(Num(a1 -> a0))
選擇后者,除了事實不同之外?
2)嗨,對於前者,當您說“但是函數沒有Num實例”時,您是什么意思? 抱歉,我不清楚實例的概念是什么。 此外,出於好奇,您是否可以使用實例Num (a -> b)
方法以某種方式告訴解釋器將3 4
解釋為4 modulo 3
?
我的意圖是用更多的解釋來補充ehird的回答。 當你寫表達
3 4
然后,Haskell解釋器認為您正在嘗試將函數3
應用於4
。 為了讓Haskell將3
解釋為一個函數,需要調用該函數
fromInteger :: Integer -> (a -> b)
為了從整數3
獲得函數(即類型a -> b
某種東西)。 現在,在Num
類型類中將fromInteger
定義為具有簽名
instance Num x where
fromInteger :: Integer -> x
例如,當將類型x
設為Num
類的實例時,將提供fromInteger
的實現,該實現告訴Haskell如何將整數文字轉換為x
。 在您的情況下, x
是函數類型a -> b
。 讓我們開始吧!
首先,一些樣板。 要使x
成為Num
Haskell的實例,還需要使它也成為Show
和Eq
的實例:
instance Show (a -> b) where show f = "<function>"
instance Eq (a -> b) where f == g = False
現在假設我們要將3 4
解釋為“ 4模3”。 然后,我們需要告訴Haskell如何將任何整數解釋為調用mod
的函數。 此外,由於mod
僅接受整數類型(它具有簽名mod :: Integral a => a -> a -> a
),因此我們還需要將a
和b
的類型也限制為整數:
instance (Integral a, Integral b) => Num (a -> b) where
要創建Num
的實例,我們需要提供(+)
, (-)
, (*)
和fromIntegral
(實際上,我們也應該定義幾個其他函數,但是現在就不用擔心了)。
有一種相當自然的方法來定義加法,減法和乘法(此處的所有代碼構成Num
實例的一部分,應相對於實例聲明縮進)
f + g = \x -> f x + g x
f - g = \x -> f x - g x
f * g = \x -> f x * g x
即,當您添加兩個函數f
和g
,您將獲得一個將f
和g
到其參數的新函數,然后將它們加在一起。 由於我們要求應用f
和g
結果是整數類型,因此我們知道將它們的輸出相加是有意義的。
要將整數解釋為函數,我們可以編寫
fromInteger n = \m -> fromIntegral m `mod` fromIntegral n
即,當我們有一個整數n
,我們返回一個參數m
的函數,該函數在被調用時確保兩個參數的類型相同(通過對這兩個參數都調用fromIntegral
),然后將它們用作函數mod
參數。
最后,還有更多樣板可以阻止Haskell抱怨:
abs f = undefined
signum f = undefined
我們可以測試一下。 我的代碼放在一個名為numfun.hs的文件中。 我啟動Haskell解釋器並加載我的文件:
Prelude> :l numfun.hs
[1 of 1] Compiling Main ( numfun.hs, interpreted )
Ok, modules loaded: Main.
現在,我可以定義一些功能:
*Main> let f = (+ 1)
*Main> let g = (* 2)
我可以添加或減去它們:
*Main> (f + g) 3 -- (3+1) + (3*2)
10
*Main> (f - g) 3 -- (3+1) - (3*2)
-2
我可以將數字稱為函數:
*Main> 3 4 -- 4 `mod` 3
1
發生第一個錯誤是因為帶有4
的整數文字可以是具有Num
實例的任何類型。 也就是說, 4
具有(Num a) => a
的類型,因此它可以用作Integer
, Double
, Rational
等。由於將3
應用於自變量( 4
),因此它在上下文中知道3
必須為函數類型(例如,對於a0
和t0
a0 -> t0
t0
)。 但是沒有函數的Num
實例,因此將3
用作函數是無效的。 如果添加了instance Num (a -> b)
,它將可以工作,但您可能不想這樣做。
至於后者,這兩個錯誤消息是等效的。 GHC生成的名稱沒有特殊含義。 字母通常從您使用的函數類型中的類型變量派生,並附加數字以使內容明確。 在這種情況下,第二個表達式等效於(+) 2 (3 4)
(因為函數應用程序比任何infix運算符都綁定得更緊密),它與您的第一段代碼並不完全相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.