按 fst 过滤元组列表

Filter a list of tuples by fst

我想做的不是真正解决问题,而是更多地学习如何编写 Haskell 代码,composes/utilizes 基本功能来完成它。

我有一个函数,它接受一个元组列表 (String, Int) 和一个字符串,以及 returns 一个其 fst 与给定字符串匹配的元组。 使用 filter 和 lambda 很容易做到这一点,但我现在想做的是删除最右边的参数,即。我想将该函数重构为具有相同功能的部分应用函数的组合。

原代码为:

getstat :: Player -> String -> Stat
getstat p n = head $ filter (\(n', v) -> n' == n) $ stats p

新代码是:

getstat :: Player -> String -> Stat
getstat p = head . (flip filter $ stats p) . cmpfst
    where cmpfst = (==) . fst . (flip (,)) 0  -- Wrong :-\

想法是翻转过滤器并通过给出元组列表 (stats p) 部分应用,然后组成 cmpfst。 cmpfst 应该是 String -> (String, Int) -> Bool 以便在应用 String 参数时,它变成 -> Bool 这有利于过滤器传入元组,但正如您所看到的 - 我在编写时遇到问题( ==) 以便只比较给定元组的 fst。

P.S。我知道第一个代码可能更干净;这项任务的重点不是编写干净的代码,而是学习如何通过组合解决问题。

编辑:

我很清楚在一个可能为空的列表中请求头部是一种糟糕的编程,会导致崩溃。就像前面提到的一张海报一样,使用 Maybe monad 非常简单优雅地解决了这个问题——这是我以前做过并且熟悉的任务。

我希望重点关注的是如何使 cmpfst 主要由基本功能组成。 到目前为止,我得到的最远的是:

getstat :: Player -> String -> Stat
getstat p = head . (flip filter $ stats p) . (\n' -> (==(fst n')) . fst) . (flip (,)) 0

我无法通过围绕 (==) 组合和部分应用来摆脱 (a -> Bool) lambda。对我来说,这表明我要么不明白自己在做什么,要么不可能按照我想象的方式使用 (==) 运算符。

此外,除非没有确切的解决方案,否则我将接受签名更改解决方案作为正确解决方案。我不想更改函数的签名,因为它对我来说是一种心理锻炼,而不是生产代码。

如果我正在编写这个函数,我可能会给它这样的类型签名:

getstat :: String -> Player -> Stat

这使得将定义简化为

变得容易
getstat n = head . filter ((== n) . fst) . stats

在评论中,您达到了

getstat p = head . (flip filter $ stats p) . (\n (n', v) -> n' == n)

I wonder if there's a nicer composition that can eliminate the anon f.

嗯,就在这里

\n (n', v) -> n' == n
-- for convenience, we flip the ==
\n (n', v) -> n == n'
-- prefix notation
\n (n', v) -> (==) n n'
-- let's remove pattern matching over (n', v)
\n (n', v) -> (==) n $ fst (n', v)
\n x -> (==) n $ fst x
-- composition, eta
\n -> (==) n . fst
-- prefix
\n -> (.) ((==) n) fst
-- composition
\n -> ((.) . (==) $ n) fst
-- let's force the application to be of the form (f n (g n))
\n -> ((.) . (==) $ n) (const fst $ n)
-- exploit f <*> g = \n -> f n (g n)   -- AKA the S combinator
((.) . (==)) <*> (const fst)
-- remove unneeded parentheses
(.) . (==) <*> const fst

删除 p 留作练习。