我有以下数据类型:
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'与每个值分开?
答案 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)
但是如果你想在的路上,你可以这样做:
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]
希望这可以帮助任何有类似问题的人。