2013-08-31 86 views
1

好的,所以我正在嘗試編寫一個Haskell函數,它可以有效地檢測給定的所有因子Int。根據關中this question給出的解決方案,我有以下幾點:Haskell sqrt類型錯誤

-- returns a list of the factors of n 
factors   :: Int -> [Int] 
factors n  = sort . nub $ fs where 
         fs = foldr (++) [] [[m,n `div` m] | m <- [1..lim+1], n `mod` m == 0] 
         lim = sqrt . fromIntegral $ n 

可悲的是,GHCI有含lim =等等,等等線

我讀過this answerNo instance for (Floating Int)通知我,並且提出的解決方案在直接輸入GHCi時起作用 - 它允許我通過Int致電sqrt。但是,當我的函數中看起來完全相同的代碼時,它停止工作。

我對Haskell比較新,所以我非常感謝幫助!

回答

4

當您檢查的sqrt

Prelude> :t sqrt 
sqrt :: Floating a => a -> a 

類型它需要一個浮點數。它在ghci中不起作用。你可能試過在一個數字上調用它,而ghci會推斷這個類型爲Float。

Prelude> let a = 1 :: Int 

Prelude> sqrt a 

<interactive>:5:1: 
    No instance for (Floating Int) arising from a use of `sqrt' 
    Possible fix: add an instance declaration for (Floating Int) 
    In the expression: sqrt a 
    In an equation for `it': it = sqrt a 

現在回到您的代碼。問題在於表達式[1 .. lim + 1]。算術序列只能應用於Enum a => a類型的值。由於limFloating a => a類型的,你需要要麼採取ceilingfloor將其轉換回Integral a => a。僅供參考,Integral類實例約束類型也有Enum實例。

+0

輝煌,謝謝!我已經將lim的定義修改爲lim = floor。 sqrt。 fromIntegral $ n',現在該函數完美工作。 –

+2

順便說一句,有一個內置的函數'你的foldr(++)[]':'concat' – kaan

1

您確實需要從整體投射(n :: Int)爲Double。然後你需要從sqrt獲得的Double轉換回Int。您將需要圓,因爲你使用(LIM + 1),我可以看到你需要四捨五入,使用地板:

isqrt :: Int -> Int 
isqrt i = let d :: Double 
       d = fromIntegral i 
      in floor (sqrt d) 

現在你可以在你的代碼中使用的這個代替開方。