2015-07-19 64 views
10

雖然這樣做在GHCI一些練習我輸入,並獲得以下>奇怪Haskell的表達類型貨號=>噸

ghci> (1 "one") 

<interactive>:187:1: 
    No instance for (Num ([Char] -> a0)) arising from a use of ‘it’ 
    In a stmt of an interactive GHCi command: print it 

這是一個錯誤,howeve如果我問GHCI爲表達的類型沒有給出任何錯誤:

ghci> :type (1 "one") 
(1 "one") :: Num ([Char] -> t) => t 

什麼是(1 "one")意思?

爲什麼這個表達式給出了一個錯誤,但是GHCi告訴它它是很好的類型?

Num ([Char] -> t) => t是什麼意思?

謝謝。

+1

請記住,該空間是函數應用程序運算符。 – Bergi

回答

10

哈斯克爾報告救援! (引用section 6.4.1

An integer literal represents the application of the function fromInteger to the appropriate value of type Integer.

fromInteger的類型是:

Prelude> :t fromInteger 
fromInteger :: Num a => Integer -> a 

所以1實際上是fromInteger (1 :: Integer)語法糖。你的表達的話,就是:

fromInteger 1 "one" 

哪可以寫成:

(fromInteger 1) "one" 

現在,fromInteger產生一個數字(即,一種類型的這是Num一個實例的值,作爲它的類型告訴我們)。在你的表達式中,這個數字適用於[Char](字符串"one")。 GHC正確地組合這些兩條信息推導出表達式具有類型:

Num ([Char] -> t) => t 

也就是說,這將是結果應用一個函數,這也是一個Num[Char]的(未指定類型t的)。原則上這是一種有效的類型。唯一的問題是[Char] -> t沒有Num的實例(也就是說,帶字符串的函數不是數字,這並不奇怪)。由於Sibi和Ørjan指出,在GHC 7.10和更高版本中,如果啓用FlexibleContexts GHC擴展,您將只能看到問題中提到的錯誤;如果啓用了FlexibleContexts GHC擴展,否則類型檢查器將會抱怨在類約束中有固定類型和類型構造函數(即,Char,[](->))。

+1

很好的答案。另外,如果你想在'ghci'中進行類型檢查,可以通過啓用'FlexibleContexts'上下文擴展來完成。 'let x = 1「one」'和':t x'會在'ghci'中顯示相同的類型。 – Sibi

+0

我不認爲問題是假設'FlexibleContexts' GHC擴展已啓用。類型':t(1「one」)'工作時不啓用該擴展,這不是ghci IMO的一致行爲。 – Sibi

+0

@Sibi確實。不過,如果不啓用'FlexibleContexts',沒有':t'的錯誤也會改變。 – duplode

1

TL; DR:這是一個亂七八糟的廢話類型,不值得擔心。

整數文字可以表示實現Num類型類型的任何類型的值。所以1或任何其他整數文字可以用在任何你需要一個數字的地方。

doubleVal :: Double 
doubleVal = 1 

intVal :: Int 
intVal = 1 

integerVal :: Integer 
integerVal = 1 

這使我們能夠靈活地在任何數字上下文中使用積分文字。

當你只使用一個沒有任何類型上下文的整數文字時,ghci不知道它是什麼類型。

Prelude> :type 1 
1 :: Num a => a 

ghci的是說「是‘1’是某種類型的我不知道,但我知道,無論何種類型是,該類型實現了Num類型類」。

在Haskell源中每次出現整數文字都用隱式的fromInteger函數包裝。因此,(1 "one")隱式轉換爲((fromInteger (1::Integer)) "one"),而子表達式(fromInteger (1::Integer))有一個尚未知的類型Num a => a,這也意味着它是某種未知類型,但我們知道它提供了一個類型類型的實例Num

我們也可以看到,它被應用於像一個功能"one",所以我們知道它的類型必須有形式[Char] -> a0其中a0是另一個未知類型。所以a[Char] -> a0必須相同。將它們代入Num a => a類型,我們知道1必須具有類型Num ([Char] -> a0) => [Char] -> a0),而表達式(1 "one")的類型爲Num ([Char] -> a0) => a0。請閱讀最後一類是「有某種類型的A0這是應用[Char]參數傳遞給函數的結果,而功能型是Num類的一個實例。

所以表達式本身具有有效的類型Num ([Char] -> a0) => a0

Haskell有一個名爲Monomorphism restriction的東西,其中一個方面是表達式中的所有類型變量在評估它們之前都必須有一個特定的已知類型,GHC在某些情況下使用類型默認規則,以適應但是,GHC不知道任何類型的a0它可以插入上面的那個定義了Num實例的類型表達式中,所以我t沒有辦法處理它,並且給你「No Instance for Num ...」的消息。

+1

這當然*不是*'亂碼廢話類型'。你爲什麼在你的博士說? – AJFarmar

+0

你認爲這個類型是有用和有意義的嗎? – NovaDenizen

+0

@NovaDenizen是的!例如,看到我的答案在這裏 - http://stackoverflow.com/questions/32443925/haskell-weird-expression/32444024#32444024 –

3

Haskell是一個非常靈活的語言,但也是一個非常字面意義上的邏輯。通常情況下,大多數語言中的東西只會是語法錯誤,Haskell會查看它們並嘗試用它來理解它們,其結果真的令人困惑,但實際上這只是語言規則的邏輯結果。

例如,如果我們輸入你的榜樣成Python,它主要是告訴我們「你剛纔輸入的是什麼使零感」:

Python 2.7.6 (default, Sep 9 2014, 15:04:36) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> (1 "one") 
    File "<stdin>", line 1 
    (1 "one") 
     ^
SyntaxError: invalid syntax 

紅寶石做同樣的事情:

irb(main):001:0> (1 "one") 
SyntaxError: (irb):1: syntax error, unexpected tSTRING_BEG, expecting ')' 
(1 "one") 
    ^
    from /usr/bin/irb:12:in `<main>' 

但Haskell不會輕易放棄!它把(1 "one"),而且推理說:

形式f x
  • 表達式是功能的應用,其中f已鍵入像a -> bx的類型爲af x的類型是b
  • 所以在表達式1 "one",1必須是一個函數,它需要"one"(a [Char])作爲它的參數。

然後給予Haskell對數字文字的處理,它將1轉換爲fromInteger 1 :: Num b => [Char] -> bfromIntegerNum類的一種方法,這意味着用戶可以爲任何類型提供它們自己的實現,包括[Char] -> b,如果您非常喜歡。

所以這個錯誤消息意味着Haskell不是告訴你你輸入的內容是無意義的,而是告訴你你沒有教它如何構造一個Num b => [Char] -> b類型的數字,因爲這真是奇怪的事情,需要對於表達是有道理的。