簡體   English   中英

在haskell中組成地板和sqrt

[英]composing floor and sqrt in haskell

我只是在學習haskell(為了好玩,我自己學習)並且遇到了障礙。

我的問題:

我如何定義一個函數

flrt = (floor . sqrt)

當我在文件中嘗試並編譯時,GCHi 會抱怨以下內容:

AKS.hs:11:9:
    No instance for (RealFrac Integer)
      arising from a use of `floor'
    Possible fix: add an instance declaration for (RealFrac Integer)
    In the first argument of `(.)', namely `floor'
    In the expression: (floor . sqrt)
    In an equation for `flrt': flrt = (floor . sqrt)

AKS.hs:11:17:
    No instance for (Floating Integer)
      arising from a use of `sqrt'
    Possible fix: add an instance declaration for (Floating Integer)
    In the second argument of `(.)', namely `sqrt'
    In the expression: (floor . sqrt)
    In an equation for `flrt': flrt = (floor . sqrt)

我不明白為什么結果函數不只是 Int -> Int。

我剛剛完成了 CS 的第二年並完成了基本的 PL 課程。 我聽說過,但還不太了解類型。 我嘗試通讀了一些 Haskell 教程,但這一切都超出了我的想象。

PS - 我也不明白單子是什么。 (我的搜索出現的很多其他問題都談到了這些)

PPS - 我的完整來源

bar = \a b -> if (2^a) > b
                then (a-1)
                else bar (a+1) b
foo = bar 1

flrt :: Integer -> Integer
flrt = (floor . sqrt)

aks target = if (target < 2)
                then putStr "Not a Prime.\n\n"
                else if elem (mod target 10) [0,2,4,5,6,8]
                        then putStr "Composite\n\n"
                        else if (elem target) [a^b | a <- [3,5..(flrt target)], b <- [1.. (foo target)]]

                                then putStr "Composite\n\n"--}
                            else 
                            putStr "filler"

問題是您試圖使用Integer作為輸入。 Haskell 是強類型的,這意味着沒有任何類型的隱式強制或轉換。 查看您嘗試編寫的函數的簽名:

sqrt  :: Floating a => a -> a
floor :: (RealFrac a, Integral b) => a -> b

在 GHC 推斷出的函數簽名處:

> :t floor . sqrt
floor . sqrt :: (RealFrac b, Integral c, Floating b) => b -> c

因此,要擁有一個從Integer (沒有Floating實例)到Integer的函數,您必須首先將參數轉換為Floating ,這可以通過使用fromIntegral來完成:

> :t floor . sqrt . fromIntegral
floor . sqrt . fromIntegral :: (Integral a, Integral c) => a -> c

正如 copumpkin 所說,在這里轉換為浮點實際上可能是一個壞主意,因為這會帶來精度損失,因此即使進行舍入,也可能會為足夠大的整數輸入產生不正確的結果。

我假設你正在處理將所有數字至少足夠小,他們的一些浮點表示,例如,所有的都是<10 300。 但是,例如

Prelude> round(sqrt.fromInteger$10^60 :: Double) ^ 2
1000000000000000039769249677312000395398304974095154031886336
Prelude>  {-   and not   -}     10^60    {-  == (10^30)^2 == (sqrt$10^60) ^ 2  -}
1000000000000000000000000000000000000000000000000000000000000

就絕對差異而言,這是一種方式 盡管如此,對於數字本身來說,它仍然是一個相當不錯的近似值,因此您可以將其用作算法的快速確定起點,以找到准確的結果。 您可以使用Integer s 實現 Newton/Raphson(在本例中為 AKA Heron):

flrt :: Integer -> Integer  -- flrt x ≈ √x,  with  flrt x^2 ≤ x < flrt(x+1)^2
flrt x = approx (round . (sqrt::Double->Double) . fromInteger $ x)
   where approx r
            | ctrl <= x, (r+1)^2 > x  = r
            | otherwise               = approx $ r - diff
          where ctrl = r^2
                diff = (ctrl - x) // (2*r)    -- ∂/∂x x² = 2x

         a//b = a`div`b + if (a>0)==(b>0) then 1 else 0   -- always away from 0

這現在可以按需要工作:

*IntegerSqrt> (flrt $ 10^60) ^ 2
1000000000000000000000000000000000000000000000000000000000000

在 Newton-Raphson 校正中總是遠離 0 的除法在這里是必要的,以防止陷入無限遞歸。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM