我在使用函数来删除Haskell中的三个参数时遇到了麻烦。
免责声明:不是课程作业,我今天被这个问题困扰的人问了这个问题,这一直困扰着我。
我们获得的自定义类型/函数是(只能记住类型)
type MyThing
= (Char, String)
type MyThings
= [MyThing]
funcA :: MyThings -> String -> String
funcB :: MyThings -> String -> Int -> String
我们从:
开始funcB as str n = iterate (funcA as) str !! n
将其减少如下:
funcB as str n = iterate (funcA as) str !! n
funcB as str = (!!) . (iterate (funcA as)) str
funcB as = (!!) . (iterate (funcA as))
funcB as = (!!) . (iterate . funcA) as
然后,卡住了。我们无法弄清楚如何避免使用最后一个参数。我知道我以前见过类似的情况并且有一个解决方案。
希望一些Haskell天才可以指出为什么我是一个白痴......
答案 0 :(得分:11)
这里您需要的是以下三个操作员部分的“法律”:
(a `op` b) = (a `op`) b = (`op` b) a = op a b
(1) (2) (3)
以便操作数进入操作员附近的空闲位置。
对于(.)
,这意味着:(a . b) = (a .) b = (. b) a = (.) a b
。所以,
f (g x) y !! n
= (!!) (f (g x) y) n by (3)
= ((!!) . f (g x)) y n
= ((!!) . (f . g) x) y n
= ((!!) .) ((f . g) x) y n by (1)
= (((!!) .) . (f . g)) x y n
= (((!!) .) . f . g) x y n
你应该只做你喜欢的那么多的无点变换,这样结果表达式仍然可以给你 - 事实上,更清晰比原版的。 “pointfree”工具有时会产生难以理解的结果。
完全可以在中间停下来。如果您手动完成它太难了,可能您也很难阅读它。
((a .) . b) x y = (a .) (b x) y = (a . b x) y = a (b x y)
是常见模式,您很快就会立即学会识别。所以上面的表达式可以很容易地回读为
(!!) ((f . g) x y) n = f (g x) y !! n
考虑到(.)
是关联的:
(a . b . c) = ((a . b) . c) = (a . (b . c))
答案 1 :(得分:10)
funcB = ((!!) .) . iterate . funcA
我认为你做了所有艰苦的工作,只剩下一小步了。
您确实可以使用pointfree自动执行此操作。请参阅HaskellWiki page
正如github readme中所述,您安装后,可以使用
修改ghci.conf
或.ghci
文件
:def pf \str -> return $ ":! pointfree \"" ++ str ++ "\""
然后在键入
时在ghci中:pf funcB as = (!!) . (iterate . funcA) as
甚至
:pf funcB as str n = iterate (funcA as) str !! n
你得到了
funcB = ((!!) .) . iterate . funcA
答案 2 :(得分:5)
对 me 的关键观察是中缀运算符可以写成前缀:
funcB as = (!!) . (iterate . funcA) as
funcB as = (.) (!!) ((iterate . funcA) as)
一旦你到了这里,你就有一半的机会认识到这是一个作文,第一个参数为(.) (!!)
,第二个参数为iterate . funcA
:
funcB as = ( ((.) (!!)) . (iterate . funcA) ) as
现在很清楚如何简化这一点;在那之后,关于如何写它有很多美学选择。例如,我们可能会发现(.)
是关联的,因此我们可以删除一些括号;同样,如果您认为它更具可读性,我们可以使用运算符部分合并难看的((.) (!!))
。
funcB = ( ((.) (!!)) . (iterate . funcA) )
funcB = (.) (!!) . iterate . funcA -- uncontroversial parenthesis removal
funcB = ((!!) .) . iterate . funcA -- possibly controversial section rewrite
顺便说一下,我认为你推导的开始是正确的。你得出了正确的结论,但通过不正确的中间步骤。更正了,它应该是这样的:
funcB as str n = iterate (funcA as) str !! n
funcB as str n = (!!) (iterate (funcA as) str) n
funcB as str = (!!) (iterate (funcA as) str)
funcB as = (!!) . iterate (funcA as)