简体   繁体   English

如何在Haskell列表中获取元素?

[英]How to get an element in a Haskell list?

I want to make a function that looks up a String in a list of type [(String, Int)] and returns the Int paired with the String . 我想制作一个在[(String, Int)]类型列表中查找String并返回与String配对的Int的函数。

Like this: 像这样:

λ> assignmentVariable "x" [("x", 3), ("y", 4), ("z", 1)]
3

Here's what I've tried: 这是我尝试过的:

assignmentVariable :: String -> [(String, Int)] -> Int
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n
                              then xs
                              else assignmentVariable

How could I write this? 我怎么写这个?

Let's take the posted code: 让我们来看看发布的代码:

assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...

The first equation has only one argument, while the second has two. 第一个方程只有一个参数,第二个方程只有两个参数。 Let's fix that. 让我们修复它。

assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ []     = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...

Since we do x == n , these variables must be of the same type. 由于我们执行x == n ,因此这些变量必须是同一类型。 However, n::String and x::(String,Integer) . 但是, n::Stringx::(String,Integer) We need to split x into its components before comparing. 在比较之前,我们需要将x拆分为其组成部分。

assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ []         = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then xs else ...

The result xs is a list, not an Integer as the type signature suggests. 结果xs是一个列表,而不是类型签名所建议的Integer You just want x there. 你只想x那里。

assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ []         = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then x else ...

Finally, the recursive call. 最后,递归调用。 When m/=n , we want to try the other pairs in the list xs , so: m/=n ,我们想尝试列表xs的其他对,所以:

assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ []         = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n 
                                  then x
                                  else assignmentVariable n xs

You want to pattern-match on the pair. 您想在这对上进行图案匹配。

assignmentVariable expected ((key, value) : rest)

If the variable name matches the expected name, the first element of the pair… 如果变量名称与预期名称匹配,则该对中的第一个元素…

  = if key == expected

You return the associated value, the second element of the pair. 您返回关联的值,这对值的第二个元素。

    then value

Otherwise, you try to find the value in the rest of the list. 否则,您尝试在列表的其余部分中找到该值。

    else assignmentVariable expected rest

You can implement it without pattern-matching, of course: 当然,您可以实现它而无需模式匹配:

assignmentVariable expected list
  = if expected == fst (head list)
    then snd (head list)
    else assignmentVariable expected (tail list)

However, this is not the usual style in Haskell code. 但是,这不是Haskell代码中的常用样式。

This function also exists in the Prelude, by the name of lookup . 此功能也存在于Prelude中,名称为lookup

You're halfway there, actually! 实际上,您已经到了一半!

First, it would be better to make a more general type signature, and a better name: 首先,最好创建更通用的类型签名和更好的名称:

myLookup :: (Eq a) => a -> [(a, b)] -> b

You've done well to have sorted out the edge case of [] , but you've not quite finished: 您已经很好地整理了[]的边缘情况,但还没有完成:

myLookup _       []     = error "myLookup: empty list."
myLookup n  ((x, b):xs) = if x == n
                          then b
                          else myLookup n xs

Your problem was what you put after the else : you weren't recursively calling the function, you were returning the function, which doesn't make any sense - you need to call it again with different arguments to recur. 您的问题是放在else之后的问题:您没有递归调用该函数,而是在返回该函数,这没有任何意义-您需要使用不同的参数再次调用它以进行递归。


If you want to improve, try making a similar function of type Eq a => a -> [(a, b)] -> Maybe b for a challenge. 如果要改进,请尝试使用类型类似的函数Eq a => a -> [(a, b)] -> Maybe b来挑战。

Just for posterity, I would like to propose an alternative implementation: 为了后代,我想提出一个替代实现:

assignmentVariables :: Eq a => a -> [(a, b)] -> [b]
assignmentVariables n xs = [v | (n', v) <- xs, n == n']

You can run it in ghci: 您可以在ghci中运行它:

> assignmentVariables "x" [("x", 3), ("y", 4), ("z", 1)]
[3]

"Ah!", I hear you say, "But it returns [3] and not 3 !". 我听到您说:“啊!但是它返回[3]而不是3 !”。 But don't give up on it yet; 但是不要放弃它。 there are several advantages of the behavior of this function over the behavior you proposed. 与您建议的行为相比,此功能的行为有几个优点。

The type of assignmentVariables is more honest than the type of assignmentVariable . 该类型的assignmentVariables比类型更诚实assignmentVariable It doesn't promise to return a value when it doesn't find the given key in its lookup table. 当在查找表中找不到给定的键时,它不承诺返回值。 This means that, unlike your version, this version will not cause runtime crashes. 这意味着,与您的版本不同,该版本不会导致运行时崩溃。 Moreover, it has a clean way to report the unlikely situation where there are conflicts in the lookup table: it will return all values associated with the given key, even if there are many. 而且,它有一种干净的方法来报告在查找表中发生冲突的可能性不大的情况:即使有很多键,它也会返回与给定键关联的所有值。

The consumer of the call then gets to decide how to handle the exceptional cases: one can write 然后,电话的使用者可以决定如何处理特殊情况:一个人可以写

case assignmentVariables key lookupTable of
    []      -> -- do something appropriate to complain about missing keys
    [value] -> -- do something with the value
    values  -> -- do conflict resolution; for example, use the first value or complain or something

or may simply treat the output of assignmentVariables as a nondeterministic value. 或者可以简单地将assignmentVariables的输出视为不确定性值。 The key here is that you are not locked into one behavior (which, of all the choices, crashing ? really?). 这里的关键是您不会陷入一种行为中(在所有选择中,哪一种都会崩溃 ?真的吗?)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM