gpt4 book ai didi

haskell - Haskell中的Eta减少

转载 作者:行者123 更新时间:2023-12-04 05:28:40 25 4
gpt4 key购买 nike

在haskell中我尝试了很久减少这个函数,我想表达例如:

mySum x y = x + y
mySum x y = (+) x y
mySum x = (+) x
mySum = (+) -- it's Messi's goal!

我的函数有点复杂,但我真的做不到,我到处看看,我知道有一些技巧,比如修改右侧,并使用 flip .我试过了,我被困在这里:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f x y = map (uncurry f) (zip x y)

脚步:
zipWith' f x y  = map  (uncurry f) (zip x y) 
zipWith' f x y = flip map (zip x y) (uncurry f)
zipWith' f x y = flip map (zip x y) $ uncurry f

然后我不知道如何继续......

我正在寻找一个可以逐步解释如何实现“梅西的目标”的答案,我知道有很多问题要问,所以我会尽快添加赏金以感谢您的努力

最佳答案

zipWith' f x y = map (uncurry f) (zip x y)

将应用程序重写为组合和 eta-reduce:
-- \y -> let g = map (uncurry f); h = zip x in (g . h) y
-- let g = map (uncurry f); h = zip x in g . h

zipWith' f x = map (uncurry f) . zip x

将中缀重写为前缀:
-- g . h = (.) g h

zipWith' f x = (.) (map (uncurry f)) (zip x)

将应用程序重写为组合和 eta-reduce:
-- \x -> let g = (.) (map (uncurry f)); h = zip in (g . h) x
-- let g = (.) (map (uncurry f)); h = zip in g . h

zipWith' f = (.) (map (uncurry f)) . zip

将中缀重写为前缀:
-- g . h = (.) g h

zipWith' f = (.) ((.) (map (uncurry f))) zip

使用 flip搬家 f到右手边:
-- flip f x y = f y x

zipWith' f = flip (.) zip ((.) (map (uncurry f)))

将应用程序重写为组合:
-- g (h (i x)) = (g . h . i) x

zipWith' f = flip (.) zip (((.) . map . uncurry) f)

将应用程序重写为组合和 eta-reduce:
-- \f -> let g = flip (.) zip; h = (.) . map . uncurry in (g . h) f
-- let g = flip (.) zip; h = (.) . map . uncurry in g . h

zipWith' = (flip (.) zip) . ((.) . map . uncurry)

删除多余的括号:
zipWith' = flip (.) zip . (.) . map . uncurry

如果您愿意,可以简化为中缀:
zipWith' = (. zip) . (.) . map . uncurry

但是,这个结果不是很可读。

通常在编写完全无点代码时,您希望利用 ->来自 Control.Arrow 的应用程序和箭头组合器.而不是尝试编写像 \ f x y -> ... 这样的函数,您可以首先将参数分组到元组中,以使它们更容易重新排列和传递。在这种情况下,我将使用 \ (f, (x, y)) -> ...
\ (f, (x, y)) -> map (uncurry f) (zip x y)

我们可以消除 (x, y) 的拆包通过申请 uncurryzip :
\ (f, (x, y)) -> map (uncurry f) (uncurry zip (x, y))
\ (f, xy) -> map (uncurry f) (uncurry zip xy)

现在我们有一个简单的例子:将两个函数( uncurryuncurry zip )应用于两个参数( fxy ),然后组合结果(与 map )。为此,我们可以使用 ***来自 Control.Arrow 的组合器, 类型:
(***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')

专门用于功能,即:
(***) @(->) :: (b -> c) -> (b' -> c') -> (b, b') -> (c, c')

这只是让我们将一个函数应用于一对中的每个元素。完美的!
uncurry *** uncurry zip
:: (a -> b -> c, ([x], [y])) -> ((a, b) -> c, [(x, y)])

你可以想到 uncurry f使用函数 f 组合一对元素.所以在这里我们可以使用 uncurry map 组合结果:
uncurry map . (uncurry *** uncurry zip)
:: (a -> b -> c, ([a], [b])) -> [c]

你可以想到 curry就像将元组上的函数转换为多参数函数一样。这里我们有两个级别的元组,外部 (f, xy)和内部 (x, y) .我们可以用 curry 打开外面的那个:
curry $ uncurry map . (uncurry *** uncurry zip)
:: (a -> b -> c) -> ([a], [b]) -> [c]

现在,你可以想到 fmap f->应用为“跳过”第一个参数:
fmap @((->) _) :: (a -> b) -> (t -> a) -> t -> b

所以我们可以使用 fmap curry 解压第二个元组。 :
fmap curry $ curry $ uncurry map . (uncurry *** uncurry zip)
:: (a -> b -> c) -> [a] -> [b] -> [c]

我们完成了!或者不完全。在编写无点代码时,将事物分解为许多名称更清晰的可重用小函数是值得的,例如:
zipWith' = untuple2 $ combineWith map apply zipped
where
untuple2 = fmap curry . curry
combineWith f g h = uncurry f . (g *** h)
apply = uncurry
zipped = uncurry zip

然而,虽然知道这些技术是有用的,但所有这些只是徒劳的诡计,很容易迷失。大多数时候,你应该只在 Haskell 中使用无点风格,当它明显赢得可读性时,这些结果都没有比简单的原始版本更清晰:
zipWith' f x y = map (uncurry f) (zip x y)

或部分无点版本:
zipWith' f = map (uncurry f) .: zip
where (.:) = (.) . (.)

关于haskell - Haskell中的Eta减少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47042731/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com