4

我正在自学 Haskell,虽然这是迄今为止最有启发性的经历,但我发现在 C 语言家族中很容易完成的一些事情仍然是个谜。所以,这是我非常基本的问题。我想要一个函数来提取具有等于给定值的某个字段的元组。到目前为止我有这个代码

withJob :: [(String, String, String)] -> String -> [String]
withJob [] _ = []
withJob ((_,_,x):xs) job
| job == x = x:(withJob xs job)
| otherwise = (withJob xs job)

users :: [(String, String, String)]
users = [("Jack", "22", "Programmer"), ("Mary", "21", "Designer"), ("John", "24", "Designer")]

当这样调用users 'withJob' "Programmer"它时,它会输出,["Programmer"]但我希望它输出[("Jack", "22", "Programmer")],但是我不知道如何访问元组而不是中的 job( x)job == x = x:(withJob xs job)

4

2 回答 2

8

为此使用@-patterns:

withJob :: [(String, String, String)] -> String -> [(String, String, String)]
withJob [] _   = []
withJob (t@(_,_,x):xs) job
   | job == x  = t : withJob xs job
   | otherwise =     withJob xs job
于 2013-04-02T18:45:56.587 回答
4

扩展@Ingo 的意思:写成Haskell 会更惯用:

jobField :: (String, String, String) -> String
jobField (_, _, j) = j

withJob :: [(String, String, String)] -> String -> [(String, String, String)]
withJob xs job = filter (\x -> jobField x == job) xs

我们可能会更进一步:

data Person = Person { pName :: String, pAge :: Int, pJob :: String }

filterbyJob :: String -> [Person] -> [Person]
filterbyJob job xs = filter (\p -> pJob p == job) xs

即便如此:

filterbyJob :: String -> [Person] -> [Person]
filterbyJob job = filter (\p -> pJob p == job)

甚至:

filterbyJob :: String -> [Person] -> [Person]
filterbyJob job = filter ((== job) . pJob)

在这一点上,除非你要使用filterByJob很多东西,否则它可能除了写filter ((== job) . pJob)你需要的地方之外没有真正的价值!

这个练习的重点是有一个强大的功能filter,人们可以直接使用,而不是每次都重写那种代码模式。它不仅可以节省您的时间和代码,而且通过重用已知函数,您可以让未来的程序员(包括未来的自己!)更容易理解代码。

于 2013-04-03T06:37:43.353 回答