柯里3个参数在Haskell(Currying 3 Arguments in Haskell)

2019-06-18 17:25发布

我在与钻营的功能,在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的天才可以指出为什么我是一个傻瓜...

Answer 1:

所有你需要的这里是操作部分的三个“规律”:

(a `op` b) = (a `op`) b = (`op` b) a = op a b
          (1)          (2)          (3)

从而使操作进入操作附近的空闲插槽。

(.)这意味着: (a . b) = (a .) b = (. b) a = (.) ab 所以,

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改造,使产生的表达式仍然可读适合你 -而事实上,比原来更清晰 。 该“pointfree”工具有时可以产生不可读的结果。

它也完全可以在中途停止。 如果是太难为你手工完成它,因为这可能是你很难读它了。

((a .) . b) xy = (a .) (bx) y = (a . bx) y = a (bxy)是,你很快就能学会立即识别常见的模式 。 因此,上述表达式可以回读很容易的

(!!) ((f . g) x y) n = f (g x) y !! n

考虑到(.)是关联:

(a . b . c) = ((a . b) . c) = (a . (b . c))


Answer 2:

funcB = ((!!) .) . iterate . funcA

我认为你做所有的辛勤工作,并有一只离开寸步。

你可以用确实这样做自动pointfree 。 见HaskellWiki页

由于它在说github上自述 ,一旦你安装了它,您可以编辑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


Answer 3:

我来说 ,关键的发现是,中缀运算符可以写成前缀:

funcB as = (!!) . (iterate . funcA) as
funcB as = (.) (!!) ((iterate . funcA) as)

一旦你在这里得到了,你必须认识到这是一种组合物,用一半的机会(.) (!!)作为第一个参数和iterate . funcA 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)


文章来源: Currying 3 Arguments in Haskell