2011-09-19 57 views
6

所以我玩這個周圍:獲取型積分一個的值=>並[a]從一個積分的值=>([A],[A],[A])

factors :: Integral a => a -> [a] 
factors n = filter (\d -> n `rem` d == 0) . takeWhile (\d -> d*d <= n) $ [ 1 .. ] 

abundants_perfects_deficients :: Integral a => ([a],[a],[a]) 
abundants_perfects_deficients = foldr switch ([],[],[]) [1..] 
    where switch :: Integral a => a -> ([a],[a],[a]) -> ([a],[a],[a]) 
     switch n (as,ps,ds) = 
      let t = sum (factors n) in 
       if t < n then (as,ps,n:ds) 
      else if t == n then (as,n:ps,ds) 
      else     (n:as,ps,ds) 

雖然我有abundants_perfects_deficients,我寧願有三個值:abundants,perfectsdeficients所有類型Integral a -> [a]

一兩件事,不工作是:

abundants,perfects,deficients :: Integral a => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients 

因爲這限制了三都是在同一a

我試圖事做他們一個接一個,所以他們不會互相制約,但沒有工作,要麼:

perfects :: Integral a => [a] 
(_,perfects,_) = abundants_perfects_deficients 

因爲編譯器無法弄清楚如何轉換類型forall a. Integral a => ([a],[a],[a])的值爲(t1, forall a. Integral a => [a], t2)

這似乎足夠的cromulent。

現在我知道我可以單獨執行這些(只是perfects = filter isPerfect [1..]),或將其約束到所有相同類型的((abundants,perfects,deficients) = abundants_perfects_deficients工作正常,如果abundants,perfects,deficients :: [Integer]),但

  • 我喜歡使用共享信息來建立所有三個
  • 我想不只是被限制爲Integer小號

想法?


編輯:讓人着迷足夠的這個作品:

abundants :: Integral a => [a] 
abundants = f as 
    where as :: [Integer] 
     (as,_,_) = abundants_perfects_deficients 
     f :: Integral a => [Integer] -> [a] 
     f = map fromInteger 

但這並不:

abundants_perfects_deficients' :: (Integral a,Integral p, Integral d) => ([a],[p],[d]) 
abundants_perfects_deficients' = (f as, f ps, f ds) 
    where as,ps,ds :: [Integer] 
     (as,ps,ds) = abundants_perfects_deficients 
     f :: Integral a => [Integer] -> [a] 
     f = map fromInteger 

abundants,perfects,deficients :: (Integral a) => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients' 

我不知道爲什麼。

回答

7

這涉及到多態類型的真正含義是什麼,這是稍微比他們第一次的顯示更加複雜。

在這一點上可能更容易轉換思維方式,並在量詞看成是拉姆達抽象形式:像∀ a. [a] A型是這樣一個功能採取單一類型的參數,並返回一個列表這種類型的東西。像Integral a這樣的類約束可以被視爲額外的參數(具體來說,實例字典),當GHC爲您找到值時,它們將被隱式提供。

爲了強調這一點,我將寫出量詞爲/\ a ->來模仿lambda語法,並將類約束寫爲常規參數。

用這種方式寫的,abundants_perfects_deficients的類型是/\a -> Integral a -> ([a],[a],[a]),並且您的初始嘗試失敗,主要是因爲您試圖對雙參數函數的結果進行模式匹配。在許多情況下,GHC會自動混洗這些隱含的爭論以使事情順利進行,但這裏很明顯不能 - 從abundants_perfects_deficients得到任何結果,您首先需要將它應用於兩個參數,得到單態結果,然後使用該模式綁定。即使模式只綁定了一個值,其餘的仍然是_,但GHC仍然需要對模式綁定本身進行類型檢查,所以即使看起來額外的參數可能會浮出到單個綁定的標識符上,也會失敗原因是一次綁定所有三個。

要將三個多態值綁定到一個模式,您需要額外的參數放在裏面,給abundants_perfects_deficients一個像(/\a -> Integral a -> [a], /\a -> Integral a -> [a], /\a -> Integral a -> [a])這樣的類型。這需要the ImpredicativeTypes extension,這有點過去了,我仍然很謹慎。

很多讓你跳動的東西是,GHC不夠聰明來找出「明顯」的東西,例如基於綁定的特定部分內使用的浮動隱式類型和約束參數。考慮到它已經在幕後做了多少魔術,這並不會讓我感到困擾。 :]

最簡單的解決方案是將所有三個分開綁定,使用選擇功能提取單個元素。這可以讓頂級綁定以預期的方式呈現多態,並且隱含的參數被隱式地傳遞給abundants_perfects_deficients,並且投影函數在(現在是單形的)模式匹配之後簡單地丟棄其他三個。

3
abundants,perfects,deficients :: Integral a => [a] 
(abundants,perfects,deficients) = abundants_perfects_deficients 

嘗試:

fst3 (a,_,_) = a 
snd3 (_,a,_) = a 
thd3 (_,_,a) = a 

abundants,perfects,deficients :: Integral a => [a] 
abundants = fst3 . abundants_perfects_deficients 
perfects = snd3 . abundants_perfects_deficients 
deficients = thd3 . abundants_perfects_deficients 
+0

將無法​​正常工作:'FST ::(A,B) - >一個'(和snd類似),你將不得不提供一些新的三元組訪問器;) –

+0

Ops,你是對的。更新以修復它。 – nulvinge

+0

需要刪除你的(。)運算符(abundants_perfects_deficients不是函數) – rampion

1

fromIntegral可能是有用的:

Prelude> :t fromIntegral 
fromIntegral :: (Num b, Integral a) => a -> b 
1

可能略有偏差,但無論如何。

factors功能失常(嘗試計算factors 28;)

這裏有一個不同的解決問題的方法:

classifieds = map (\n -> (n, compare n (sum $ factors n))) [1..] 

perfects = map fst $ filter ((== EQ) . snd) classifieds 
abundants = map fst $ filter ((== GT) . snd) classifieds 
deficients = map fst $ filter ((== LT) . snd) classifieds 
+0

哎呦:)也是好主意。 – rampion

相關問題