在Haskell中讨论3个参数

Pet*_*ton 7 haskell pointfree

我在使用函数来删除Haskell中的三个参数时遇到了麻烦.

免责声明:不是课程作业,今天有人在挣扎着问我这个问题,这一直困扰着我.

我们给出的自定义类型/函数是(只能记住类型)

type MyThing
  = (Char, String)
type MyThings
  = [MyThing]

funcA :: MyThings -> String -> String
funcB :: MyThings -> String -> Int -> String
Run Code Online (Sandbox Code Playgroud)

我们开始:

funcB as str n = iterate (funcA as) str !! n
Run Code Online (Sandbox Code Playgroud)

并将其减少如下:

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
Run Code Online (Sandbox Code Playgroud)

然后,卡住了.我们无法弄清楚如何避免使用最后一个参数.我知道我以前见过类似的情况并且有一个解决方案.

希望一些Haskell天才可以指出为什么我是一个白痴......

Wil*_*ess 13

这里你需要的是以下三个操作员部分的"法则":

(a `op` b) = (a `op`) b = (`op` b) a = op a b
          (1)          (2)          (3)
Run Code Online (Sandbox Code Playgroud)

以便操作数进入操作员附近的空闲槽.

对于(.)这意味着:(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
Run Code Online (Sandbox Code Playgroud)

你应该只做你喜欢的那么多的无点转换,这样结果表达式对你来说仍然是可读 - 事实上,它比原来更清晰."无点"工具有时会产生难以理解的结果.

停在中间是完全可以的.如果您手动完成它太难了,可能您也很难阅读它.

((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
Run Code Online (Sandbox Code Playgroud)

考虑到这(.)是关联的:

(a . b . c) = ((a . b) . c) = (a . (b . c))
Run Code Online (Sandbox Code Playgroud)


And*_*ewC 11

funcB = ((!!) .) . iterate . funcA
Run Code Online (Sandbox Code Playgroud)

我认为你做了所有艰苦的工作,只剩下一小步了.

您确实可以使用pointfree自动执行此操作.请参阅HaskellWiki页面

由于它在说github上自述,一旦你安装了它,您可以编辑ghci.conf.ghci一行的文件

:def pf \str -> return $ ":! pointfree \"" ++ str ++ "\""
Run Code Online (Sandbox Code Playgroud)

然后在你输入时的ghci

:pf funcB as = (!!) . (iterate . funcA) as
Run Code Online (Sandbox Code Playgroud)

甚至

:pf funcB as str n = iterate (funcA as) str !! n
Run Code Online (Sandbox Code Playgroud)

你得到

funcB = ((!!) .) . iterate . funcA
Run Code Online (Sandbox Code Playgroud)

  • 那不是eta减少.Eta减少正从'\ x - > ex`变为`e`.你给出的转换(从`\ x - > f(gx)`转换到`f.g`)是另一回事 - 也许是`(.)`的​​delta扩展? (3认同)

Dan*_*ner 5

来说关键的观察是中缀运算符可以写成前缀:

funcB as = (!!) . (iterate . funcA) as
funcB as = (.) (!!) ((iterate . funcA) as)
Run Code Online (Sandbox Code Playgroud)

一旦你到了这里,你有一半的机会认识到这是一个作文,(.) (!!)作为第一个参数和iterate . funcA第二个参数:

funcB as = (  ((.) (!!)) . (iterate . funcA)  ) as
Run Code Online (Sandbox Code Playgroud)

现在很清楚如何简化这一点; 在那之后,关于如何写它有很多美学选择.例如,我们可能会观察到它(.)是关联的,因此我们可以删除一些括号; 同样,((.) (!!))如果您认为它更具可读性,我们可以使用运算符部分来合并难看的.

funcB = (  ((.) (!!)) . (iterate . funcA)  )
funcB = (.) (!!) . iterate . funcA -- uncontroversial parenthesis removal
funcB = ((!!) .) . iterate . funcA -- possibly controversial section rewrite
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我不认为你的推导的开始是正确的.你得出了正确的结论,但通过不正确的中间步骤.更正了,它应该如下所示:

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)
Run Code Online (Sandbox Code Playgroud)