对自定义数据类型执行操作?

时间:2016-09-27 09:31:52

标签: haskell types

我有以下数据类型:

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 ‘+’"

我该如何使这项工作?我是否需要将'Age'与每个值分开?

4 个答案:

答案 0 :(得分:8)

首先,错误消息告诉您正在使用(+)上的Users函数,但未对​​其进行定义。

因此,您可以将Users设为Num的实例,这意味着您还需要为(-)(*)negate,...定义{ {1}},这似乎很奇怪。

也许你需要这样的东西:

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

答案 1 :(得分: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]

答案 2 :(得分:1)

@Schoon是对的。

但是如果你想在的路上,你可以这样做:

data Users = Height Int | Age Int deriving (Show)你必须“衍生”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]

然后,你变成了这个:

*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> 
好的,不是吗? :)

答案 3 :(得分:-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]

希望这可以帮助任何有类似问题的人。