2017-04-18 65 views
0

當我嘗試提取數字的前兩位數字時,出現令人沮喪的錯誤。首先,我使用日誌計算出數字的長度,然後將數字除以10^(length of digit - 2)以提取前兩位數字。 len和divisor函數工作正常,但前兩個函數失敗了,我不明白這一點,因爲它看起來很直觀。我什至嘗試加入{-# LANGUAGE FlexibleContexts #-},但沒有。請協助。下面的代碼:提取一個數字的前兩位數字haskell

len n = (+) 1 $ truncate $ logBase 10 n -- length of a digit 

divisor n = 10^(len n - 2) 

firstTwo n = div n divisor 

我得到的錯誤是:

在約束

非類型變量參數:Integral (r -> a)

(Use FlexibleContexts to permit this) 
When checking that ‘firstTwo’ has the inferred type 
    firstTwo :: forall a r. 
       (Floating r, Integral (r -> a), Num a, RealFrac r) => 
       (r -> a) -> r -> a 
+0

嘗試增加類型簽名以獲得更好的錯誤。 – melpomene

+0

您還需要檢查指數是否定的。換句話說,確保你的號碼至少是2位數字。 – mathk

回答

3

ndivisor使用div,但divisor ISN」與n相同,它是一個函數。這就是爲什麼你最終得到Integral (r -> a)

使用firstTwo n = div n (divisor n),但請記住,logBase僅適用於FloatingDoubleFloat,而div僅適用於IntegralIntegerInt。因此,它仍然不會編譯,除非您更改了len的類型。

將類型簽名添加到您的函數中以獲得更好的錯誤消息。

+0

非常感謝Zeta。我現在明白這個問題。 – Amateur

3

因爲你似乎是一個初學者,我的第一個建議是,儘可能地添加類型信息。至少對於每個頂級(功能)定義。這可以幫助您,編譯器和其他讀取代碼的人理解您的意圖。

我們您的問題:您嘗試通過一個函數divisor

div n (divisor n) 

劃分若干n應該做的伎倆,也有一個小一點的缺失 - logBase對整數不起作用,而div做只能用於整數。所以你需要先撥打fromInteger進行轉換。

對負數進行小調整的替代方案可能是take 2 . show

+0

拿2。顯示作品像魅力的感謝。 – Amateur

1
  1. 將您的號碼轉換爲字符串。

  2. 檢查字符串是否包含2個或更多字符。

  3. 如果檢查成功,請從字符串中取出前2個字符並將它們轉換爲Int(或者將這些字符置於元組中,或者將它們替換爲它們)。

  4. 如果您的號碼包含少於2位的數字(例如拋出錯誤),請處理這種情況。

    firstTwo :: Integer -> Int 
    firstTwo n 
        | (length . show $ n) >= 2 = read . take 2 . show $ n 
        | otherwise = error "The number contains less than 2 digits" 
    
+0

謝謝亞瑟代碼。很棒! – Amateur