2011-03-24 51 views
0

代碼如下。我想參數給我的功能,只受到類型的限制。我在它們上調用類型類的函數,然後我可以使用它們。但我正在嘗試這樣做時遇到各種錯誤。如何接受僅限於類型類別的參數

{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, UndecidableInstances #-} 

class PlotValue a where 
    value :: a -> Double 
instance PlotValue Double where 
    value = id 
--instance PlotValue Int where 
    --value x = fromIntegral x 
instance (Integral a) => PlotValue a where 
    value x = fromIntegral x 
instance PlotValue String where 
    value x = 5 

type Input = (PlotValue a, PlotValue b) => (Maybe a, Maybe b) 

test :: Input -> String 
test (Just a, Just b) = (show $ value a) ++ (show $ value b) 

main = do 
    putStrLn (show (test (Just "strl", Just 6.4))) 

電流誤差(儘管他們改變取決於我試了一下):

Test5.hs:17:5: 
    Couldn't match expected type `Input' against inferred type `(a, b)' 
    In the pattern: (Just a, Just b) 
    In the definition of `test': 
     test (Just a, Just b) = (show $ value a) ++ (show $ value b) 

Test5.hs:20:30: 
    Couldn't match expected type `a' against inferred type `[Char]' 
     `a' is a rigid type variable bound by 
      the polymorphic type 
      `forall a b. (PlotValue a, PlotValue b) => (Maybe a, Maybe b)' 
      at Test5.hs:20:19 
    In the first argument of `Just', namely `"strl"' 
    In the expression: Just "strl" 
    In the first argument of `test', namely `(Just "strl", Just 6.4)' 

Test5.hs:20:43: 
    Could not deduce (Fractional b) 
     from the context (PlotValue a, PlotValue b) 
     arising from the literal `6.4' at Test5.hs:20:43-45 
    Possible fix: 
     add (Fractional b) to the context of 
     the polymorphic type 
      `forall a b. (PlotValue a, PlotValue b) => (Maybe a, Maybe b)' 
    In the first argument of `Just', namely `6.4' 
    In the expression: Just 6.4 
    In the first argument of `test', namely `(Just "strl", Just 6.4)' 
+0

'{ - #語言OverlappingInstances# - }'可以做的工作,但我不喜歡這樣做,而不精確知道我在做什麼 – 2011-03-24 12:25:06

+0

你將會遇到問題 - 使用值來嵌入'Input' - 我認爲同義詞定義給它一種存在型,我懷疑你在實踐中會需要它。 – 2011-03-24 12:45:02

+0

爲了擴展Stephen的觀點,你可以通過編寫'type Input a b =(PlotValue a,PlotValue b)=>(Maybe a,Maybe b)'來實現你想從類型同義詞中得到的結果。但是您至少需要使用FlexibleContext和其他擴展來完成它,而且我仍然認爲編寫'type Input ab =(Maybe a,Maybe b)'是更好的形式,然後將類型約束添加到函數類型。 – 2011-03-24 16:46:02

回答

2

修正了一些小東西。主要是,正如斯蒂芬所指出的,在類型同義詞下隱藏一個自由類型變量通常是愚蠢和不好的。

{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, OverlappingInstances, UndecidableInstances #-} 

class PlotValue a where 
    value :: a -> Double 
instance PlotValue Double where 
    value = id 
instance (Integral a) => PlotValue a where 
    value x = fromIntegral x 
instance PlotValue String where 
    value x = 5 

test :: (PlotValue a, PlotValue b) => (Maybe a, Maybe b) -> String 
test (Just a, Just b) = (show $ value a) ++ (show $ value b) 

main = do 
    putStrLn (show (test (Just "strl", Just (6.4::Double)))) 
+0

我很好奇爲什麼它很愚蠢和壞,但是...似乎擺脫了同義詞,並添加OverlappingInstances是需要的。 有什麼方法來合併/別名類型約束?例如,如果我有10個函數test1到test10,它們都包含'(PlotValue a,PlotValue b)=>(也許a,也許b)'',那麼不必將類約束放在一個地方(這就是爲什麼我把它放在類型同義詞中),而不是到處散佈。有沒有其他適當的方法可以做到這一點?謝謝! – mentics 2011-03-24 14:51:52

+0

如何構造「Value」類型的值?它的形式爲'(Just x,Just y)',但是你爲'x'和'y'寫入的內容必須佔用所有*'PlotValue'類型,而不是'某些*'PlotValue'類型。這是第二個錯誤所說的。 – applicative 2011-03-24 15:19:26

+1

@taotree:你可以定義'type Input r =(PlotValue a,PlotValue b)=>(也許a,也許b) - > r'那麼你的'test'變成'test :: Input String'。要添加一個額外的參數:'test2 :: Input(Bool - > Double)'。 – 2011-03-24 21:53:57

2

你真的需要在這裏發明新的類型類嗎?你會想,機器很複雜。這只是包含String,可能會強迫你,但還有其他方法。看起來你只需要從標準數值類型(Int,Integer,Float,Double)到Double的一般映射。有很多方法可以解決這個問題,但d這裏取代你的value

d :: Real a => a -> Double 
d = fromRational . toRational 

test (Just a, Just b) = show (d a) ++ " " ++ show (d b) 
test (_, _)= "Something's missing" 

-- Main> :t test 
-- test :: (Real a, Real a1) => (Maybe a, Maybe a1) -> [Char] 

double :: Double 
double = 1.0 
float :: Float 
float = 1.0 
int :: Int 
int = 1 
integer :: Integer 
integer = 2 

omnibus = d double * d float * d int/d integer 

jdouble = Just double 
jinteger = Just integer 

goodtest = (jdouble,jinteger) 
badtest = (Nothing, jinteger) 

main = print omnibus >> putStrLn (test goodtest) >> putStrLn (test badtest) 

-- Main> main 
-- 0.5 
-- 1.0 2.0 
-- Something's missing 

如果你想讓它適用於dString,那麼你要正確對待與數字的字符串。好的,一種方法是爲String定義一個Num實例,以創建一個Real實例。只是谷歌「實例數字字符串」,或見例如例如this remark of dons。下面是一個輕浮的例子:

instance Num String where 
    fromInteger = show 
    (+) = (++) 
    x * y = concatMap (const y) x 
    abs = undefined 
    signum = undefined 

instance Real String where toRational = toRational . d . length 
-- Main> fromInteger 500 * "moo " 
-- "moo moo moo " 
-- Main> d (fromInteger 500 * "moo") 
-- 12.0 

stringy = d "string" 
jstringy = Just stringy 
stringytest = (jstringy, jinteger) 

main' = print omnibus >> print stringy >> 
     putStrLn (test goodtest) >> putStrLn (test badtest) >> 
     putStrLn (test stringytest) 
-- Main> main' 
-- 0.5 
-- 5.0 
-- 1.0 2.0 
-- Something's missing 
-- 5.0 2.0 

或者,如果你想與value一個PlotValue型類,何不例如,它分別對四大主導數值類型和String?實際上,您似乎想要的Input類型實際上是類似於(Maybe Double, Maybe Double)

注意,如果你寫

main = do 
    putStrLn (show (test (Just "strl", Just 6.4))) 

你不需要do,因爲你只需要考慮一個動作;並且您不需要「顯示」,因爲test已經生成String

+0

我對此感到抱歉。這不是關於數字類型。這正是我選擇一個簡單的測試,試圖找出如何做一般情況。一般情況是:採取一組類型,並能夠將它們作爲單個特定類型使用。 Type類提供了將它們全部轉換爲函數可以使用的特定類型的機制。 – mentics 2011-03-24 17:26:03

+0

各種各樣的東西都可能回答這個描述,但我認爲很明顯你試圖在類型機器上強制使用錯誤的模型。很少有人有理由在Haskell中引入新類型,很常見的是有理由引入新類型,因此引入新實例。在正確定位自己之前,你似乎試圖超越類型和類型的系統。 – applicative 2011-03-24 18:53:57

+0

所以,如果我明白了:比方說,我有不同的類型,如:高度,重量,距離,速度等......所有這些都有一個量級。你建議不要創建一個Magnitude類型的類併爲這些類型添加實例,只需在現有的類型類中爲它們添加實例。這就說得通了。對當前這個問題沒有幫助(因爲它涉及到使用類型類,而不是創建一個我正在試圖制定的類),但是對於我來說,記住它是件好事。 – mentics 2011-03-24 19:53:47

1

對於周圍的(我的眼睛)「奇怪」型代名詞饒人,我會跟GADTs去,就像這樣:

{-# LANGUAGE GADTs #-} -- in addition to the rest 
data Input where 
    Input :: (PlotValue a, PlotValue b) => Maybe a -> Maybe b -> Input 
test :: Input -> String 
test (Input (Just a) (Just b)) = (show $ value a) ++ (show $ value b) 

唯一的開銷是有相匹配,對Input構造。

(關於類和實例設計的問題已經回答了,所以我不會進入他們)

+0

有趣的解決方案。爲語法糖添加開銷和複雜性可能不會最好地滿足我需要的。 – mentics 2011-03-24 17:30:01

+0

嗯,它只是鍵入(鍵盤意義上的)開銷! 'Input'數據類型體現了兩個可繪製值的概念,可能存在也可能不存在 - 您可以使用'(Just Double,Just Double)'並存儲'value'的結果。如果您稍後擴展'PlotValue'類,那麼我想我的解決方案會更靈活一點。 – yatima2975 2011-03-24 18:12:45

+0

哦,我以爲你的意思是它會有運行時性能開銷。但也許它不會(我正在處理性能嚴重的代碼),在這種情況下,這看起來很有趣。雖然我記得之前有過GADT的問題,因爲我認爲你不能在某些地方像他們和我們一樣對他們進行匹配(我認爲在某些情況下這對我來說不起作用) – mentics 2011-03-24 20:00:21

相關問題