我想要做的不是真正解决问题,而是学习如何编写Haskell代码,编写/利用基本函数来完成。
我有一个函数,它接受元组( String,Int)和字符串的列表,并返回一个tuple,其fst与给定的字符串匹配。这对于过滤器和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 )中,然后组成cmpfst。cmpfst应该是String -> ( String,Int) -> Bool,这样当String参数被应用时,它就变成了一个-> Bool,这有利于过滤器传递元组,但是正如您所看到的--我有问题组成(==),因此只比较给定元组的fst。
我知道第一段代码可能更简洁;这个任务的目的不是编写干净的代码,而是学习如何通过组合解决问题。
编辑:
我很清楚,在一个可能是空的列表上要求一个标题是一个糟糕的程序,会导致崩溃。就像前面提到的一张海报一样,它非常简单而优雅地解决了也许是单一的问题--这是我以前做过的,也是我所熟悉的。
我想要关注的是,如何使cmpfst主要由基本功能组成。到目前为止,我得到的是:
getstat :: Player -> String -> Stat
getstat p = head . (flip filter $ stats p) . (\n' -> (==(fst n')) . fst) . (flip (,)) 0我无法通过编写和部分应用-> (==)来摆脱(一个==)λ。对我来说,这意味着我要么不明白自己在做什么,要么就不可能以我想象的方式使用(==)操作符。
此外,除非没有确切的解决方案,否则我将接受签名更改方案作为正确的解决方案。我不想更改函数的签名,仅仅因为它对我来说是一种心理练习,而不是一种生产代码。
发布于 2016-03-16 17:05:51
在一条评论中,你联系了
getstat p = head . (flip filter $ stats p) . (\n (n', v) -> n' == n)我想知道是否有一种更好的成分可以消除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是作为练习留下的。
发布于 2016-03-16 15:22:53
如果我要编写这个函数,我可能会给它这种类型的签名:
getstat :: String -> Player -> Stat这使得eta很容易将定义简化为
getstat n = head . filter ((== n) . fst) . statshttps://stackoverflow.com/questions/36039245
复制相似问题