[英]Understanding types in Haskell
我正在嘗試將函數h映射到素數列表。 兩者都在下面給出:
f k x = floor ( log k / log x )
h = f 20
primes = 2 : sieve [3,5..]
where
sieve (p:xs) = p:[ x | x <- xs, x `mod` p > 0 ]
但是,當我嘗試map h primes
,出現以下錯誤:
Ambiguous type variable `a0' in the constraints:
(Enum a0)
arising from the arithmetic sequence `3, 5 .. '
等等...
函數f和素數似乎都能按預期工作,但我無法將f應用於素數中的數字??? 我在這里誤會什么?
您的函數primes
是類型[Integer]
。
您的函數h
是Double -> Integer
類型的。
map
的類型如下:
ghci> :t map
map :: (a -> b) -> [a] -> [b]
或者,當專門處理Integer
列表時,其類型簽名將變為:
map :: (Integer -> b) -> [Integer] -> [b]
但是要傳遞給map
h
函數的類型為Double- Double -> Integer
,因此不會進行類型檢查,因為它期望的是Integer- Integer -> b
而不是接受Double
的函數。
始終嘗試在功能之前編寫類型簽名,這將使您的生活更輕松。
primes :: Integral a => [a]
和h :: (RealFrac a, Integral b, Floating a) => a -> b
。 現在,沒有任何類型同時是RealFrac
和Integral
實例,但是GHC不知道這一點,因此它給出的錯誤消息有點令人困惑。
log :: Floating a => a -> a
floor :: (RealFrac a, Integral b) => a -> b
log :: Floating a => a -> a
, (/) :: Fractional a => a -> a -> a
floor :: (RealFrac a, Integral b) => a -> b
(/) :: Fractional a => a -> a -> a
floor :: (RealFrac a, Integral b) => a -> b
(/) :: Fractional a => a -> a -> a
和floor :: (RealFrac a, Integral b) => a -> b
,所以當我們撰寫他們我們得到上面的類型簽名。 Haskell具有強大的數字類型,這意味着整數和浮點類型之間沒有隱式轉換。
使用顯式轉換函數fromIntegral :: (Integral a, Num b) => a -> b
:
map (h . fromIntegral) primes
primes
有什么類型? 那完全取決於情況。 它可能是
primes :: [Integer]
或者是其他東西。 目前尚不清楚,因為像3
這樣的文字的類型為3 :: Num a => a
。 我們唯一可以確定的是,無論它是Enum
的實例是什么,否則[3,5..]
將無法工作。
現在f
是什么類型? f
使用log
作為參數,然后對結果取底,因此我們可以期待類似
f :: (RealFrac a, Floating a, Integral b) => a -> a -> b
但是,這已經暗示您不能將其與map
一起使用,因為map
需要將(a -> b)
a- (a -> b)
作為第一個參數。 更重要的是, primes
元素不滿足Floating
約束:
*Main> let (p1:p2:_) = primes
*Main> f p1 p2
<interactive>:29:1:
No instance for (RealFrac Integer) arising from a use of `f'
Possible fix: add an instance declaration for (RealFrac Integer)
In the expression: f p1 p2
In an equation for `it': it = f p1 p2
因此,我們需要更改primes
類型或f
的類型。 我們更改f
的類型:
f k x = floor ( log (fromIntegral k) / log (fromIntegral x) )
現在我們可以按預期使用f p1 p2
:
*Main> let (p1:p2:_) = primes
*Main> f p1 p2
0
但是map
問題呢? map
期望(a -> b)
a- (a -> b)
作為第一個參數,而f
仍然是(a -> b -> c)
*。 從您當前的代碼看來,您似乎想使用兩個連續的素數並應用f
。 為此,我們首先使用uncurry
:
uncurry :: (a -> b -> c) -> (a, b) -> c
現在, uncurry f
具有(a, b) -> c
。 但是現在列表(質primes
)不再是配對列表。 但是,我們可以很容易地解決此問題,我們用尾部zip
素數:
map (uncurry f) (zip primes $ tail primes)
這樣便可以在單個列表的連續元素上映射具有兩個參數的函數。
* k或x可以是不同的積分類型
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.