2016-09-27 68 views
1

我有以下數據類型:對自定義數據類型執行操作?

data Users = Height Int | Age Int 

我再有年齡的列表:

myList = [Age 44, Age 54, Age 21, Age 34, Age 22] 

,我想申請這一功能:

myFunction :: [Users] -> [Users] 
myFunction li = [x + 1 | x <- li] 

然而這個原因出現以下錯誤:

"No instance for (Num Users) arising from a use of ‘+’" 

我該如何做這項工作?我是否需要將「年齡」與每個值分開?

+4

首先:爲'Users'添加'1'意味着什麼?你期望什麼結果? – 2016-09-27 09:35:26

+0

@Rhymoid我想給值加1,即44歲變成45歲 –

+0

@barbrac一個'User'可以是'Height',不僅是'Age'。如果它是'Height'或'Age',你必須指定'(x :: User)+ 1'發生了什麼。 – user2407038

回答

8

首先,錯誤消息告訴您,您正在使用Users上的(+)函數,但未定義它。

所以,你可以讓Users實例的Num,這意味着你還需要定義(-)(*)negate,。對於Users,這似乎很奇怪。

也許你需要的東西是這樣的:

data User = User {height :: Int, age :: Int } deriving (Show) 

addToHeight :: Int -> User -> User 
addToHeight x (User h a) = User (h+x) a 

然後使用:

let users = [User 180 20, User 185 22] 
fmap (addToHeight 1) users 

-

離開語義之外:

plus :: Int -> Users -> Users 
plus x (Age a) = Age (a+x) 
plus x (Height h) = Height (h+x) 
+0

就這個答案而言,'data User = User Int Int'會更簡單。你沒有使用記錄語法。 – chepner

+0

是的。我用它作爲一種文檔。 'data Users = Height Int | Age Int'在語義上似乎不正確,並且'User Int Int'有點泛化。 – Schoon

1

@Schoon是正確的。

但是,如果你想讓它在你的方式你可以這樣做:

data Users = Height Int | Age Int deriving (Show)你要 「導出」 節目;)

則:

older :: Users -> Users 
older (Age a) = Age (a+1) 
older _  = error "not Age" --Now it's better ;) 

和你功能:

everyOneOlder :: [Users] -> [Users] 
everyOneOlder li = [older x | x <- li] 

And th en,you become this:

*Main> :l test.hs 
[1 of 1] Compiling Main    (test.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> let x = Age 5 
*Main> x 
Age 5 
*Main> let y = older x 
*Main> y 
Age 6 
*Main> let z = [Age 1, Age 2]  
*Main> everyOneOlder z 
[Age 2,Age 3] 
*Main> 

不錯,是不是? :)

+0

在ghci中使用':set -W',你會發現'older'中的模式匹配不完整。在舊的版本中添加Height案例在語義上沒有意義。 – Schoon

+0

我知道,我只是想根據自己的意願給出答案。當然,舊版的模式匹配並不完整,增加高度的情況也沒有意義,但他是這麼想的。現在他可以看到,它是如何工作的,即使這不是最佳做法。如果我做到了,我會以不同的方式做。 –

2

在你的情況我覺得你真的不想要一個新的數據類型

data Users = Height Int | Age Int 

Type synonyms應該足夠了;他們將與標準運營商很好地合作:

type Age = Int 
type Height = Int 

myList :: [Age] 
myList = [44, 54, 21, 34, 22] 

myFunction :: [Age] -> [Age] 
myFunction li = [x + 1 | x <- li] 
-1

我找到了使用Applicative Functors的最佳解決方案。

代碼:

data Users a = Height a | Age a deriving (Show, Eq, Ord) 

myList = [Age 44, Age 65, Age 21, Age 87] 

instance Functor Users where 
    fmap f (Age a) = Age (f a) 
    fmap f (Height a) = Height (f a) 

instance Applicative Users where 
    pure a = (Age a) 
    (<*>) (Age a) = fmap a 
    pure a = (Height a) 
    (<*>) (Height a) = fmap a 

main = do 
    let increaseAgesByOne = pure (\x -> pure (+1) <*> x) <*> myList 
    print $ increaseAgesByOne 

輸出:

[Age 45, Age 66, Age 22, Age 88] 

希望這有助於有類似問題的人。

+2

我可以問你,你是否確定這是你想要的? – Schoon

+0

@Schoon怎麼這樣? –

+0

它似乎沒有編譯。 。 ''純粹'' – Schoon