我正在尝试获取列表中某个值的索引,如下所示:
items = "Test"
zipItems xs = zip xs [0..]
thisItemNumber item = snd . head . filter (\(i, _) -> i == item) (zipItems items)
运行此命令时,出现以下错误:
* Couldn't match expected type `a -> [(a0, c)]'
with actual type `[(Char, Integer)]'
* Possible cause: `filter' is applied to too many arguments
In the second argument of `(.)', namely
`filter (\ (i, _) -> i == item) (zipItems items)'
In the second argument of `(.)', namely
`head . filter (\ (i, _) -> i == item) (zipItems items)'
In the expression:
snd . head . filter (\ (i, _) -> i == item) (zipItems items)
* Relevant bindings include
thisItemNumber :: Char -> a -> c (bound at <interactive>:89:5)
我不了解。在我的脑海中:
zipItems items
具有类型[(Char, Int)]
\(i, _) -> i == item
具有类型(Char, a) -> Bool
然后我只是将过滤器应用于类型a -> Bool
和a
。这怎么了?
答案 0 :(得分:7)
您在这里使用.
。 .
运算符创建函数管道:
(f . g) x = f (g x)
您的代码是
snd . head . filter (\(i, _) -> i == item) (zipItems items)
snd
是一个函数。
head
是一个函数。
但是filter (\(i, _) -> i == item) (zipItems items)
不是一个函数,它是一个列表。
这就是为什么会出现错误的原因:要使用.
,必须为其提供功能。
* Couldn't match expected type `a -> [(a0, c)]'
with actual type `[(Char, Integer)]'
说.
需要某种函数(必须返回一个元组列表才能满足snd . head
),但是您实际上给的是一个列表。
可能的解决方案:
完全不使用.
:
snd (head (filter (\(i, _) -> i == item) (zipItems items)))
所有功能都已完全应用,因此您实际上不需要功能管道。
使用$
代替括号:
snd $ head $ filter (\(i, _) -> i == item) $ zipItems items
难以嵌套的深层代码。我们可以改用)))
来摆脱$
。
构建函数管道,但立即将其应用于参数:
(snd . head . filter (\(i, _) -> i == item) . zipItems) items
现在.
的所有操作数都是函数,但我们将整个内容都考虑在内,最后将其应用于items
。
或者您可以只使用标准库并执行
import Data.List
thisItemNumber item = elemIndex item items
这会稍微将thisItemNumber
的返回类型更改为Maybe Int
,因为item
可能不会出现在items
中。如果要忽略此错误:
import Data.List
import Data.Maybe
thisItemNumber item = fromJust (elemIndex item items)
答案 1 :(得分:1)
您以某种方式编写了一个函数,看起来像是“函数管道”(使用(.)
运算符)与指定参数的方法之间的(错误)混合。
由于您定义了功能链,因此如果在此处使用zipItem items
执行功能应用程序,则需要将这些功能放在括号之间,因为否则功能应用程序仅与链条的最后一项绑定:{{1 }}。如果您写:
filter (\(i, _) -> i == item)
然后将其插入为:
f . g x
但是f . (g x)
运算符希望第二个操作数是一个函数,其中(.) :: (b -> c) -> (a -> b) -> a -> c
是filter (\(i, _) -> i == item) (zipItems items)
,因此两者 not 不匹配。>
因此,通过添加方括号,我们可以获得:
[(Char, Int)]
由于可能找不到该元素,因此使用listToMaybe :: [a] -> Maybe a
并返回一个thisItemNumber :: (Enum c, Num c) => Char -> c
thisItemNumber item = (snd . head . filter (\(i, _) -> i == item)) (zipItems items)
可能会很有用,这样很明显该函数可能无法找到该元素:
Maybe c
例如:
import Data.Maybe(listToMaybe)
thisItemNumber :: (Enum c, Num c) => Char -> Maybe c
thisItemNumber item = (listToMaybe . map snd . filter ((item ==) . fst)) (zipItems items)
话虽这么说,elemIndex :: Eq a => a -> [a] -> Maybe Int
函数已经存在(您当然打算在这里做这些事情)(当然不包含此特定值)。
所以最后一个功能等效于:
Prelude Data.Maybe> thisItemNumber 'L'
Nothing
Prelude Data.Maybe> thisItemNumber 'a'
Nothing
Prelude Data.Maybe> thisItemNumber 'T'
Just 0
Prelude Data.Maybe> thisItemNumber 'e'
Just 1
Prelude Data.Maybe> thisItemNumber 'X'
Nothing
或者我们可以用fromJust :: Maybe a -> a
从import Data.List(elemIndex)
thisItemNumber :: (Enum c, Num c) => Char -> Maybe c
thisItemNumber item = elemIndex item items
数据构造函数中解包该值:
Just
尽管如前所述,这意味着您的函数可能会出错,通常不是可取的。