[英]Haskell eta reduction using map and $ for function application
嗨,我有一個任務來編寫一個函數,該函數從Int -> Int
和單個Int
中獲取函數列表,並檢查應用於該Int
函數是否得出大於5的結果。
這是我的解決方案:
foo :: [Int -> Int] -> Int -> Bool
foo ls = any (>5) . f ls
where f ls v = map ($ v) ls
我想知道是否有一種方法可以用eta減少最后一個參數(現在是eta減少但不是單行)在單行中編寫(不使用where或let)。 我嘗試過這樣的事情:
foo ls = any (>5) . flip map ls
但是現在的問題是調用函數看起來像這樣才能正常工作
foo [(+3), (*4), (+1)] ($2)
我想避免在最后一個論點中寫$。 我嘗試過這樣的事情(和類似的事情):
foo ls = any (>5) . flip map ls ($)
但是我總是會遇到一些錯誤。 請注意,我不能更改類型簽名,也不能更改翻轉。
有辦法嗎? 當然。 可讀嗎? 不能。Haskell的設計使您擺脫一些常見的錯誤,例如不必要的可變性或(必要的)可變狀態的隱藏使用。 但是,遵循其他錯誤的方法也很令人興奮,例如以有害於可讀性和可維護性的方式使代碼毫無意義。
關於無點定義的問題是,轉換為無點定義是一個完全機械的過程(只要開始定義中不涉及模式匹配)。 有一些工具可以自動執行。
首先編寫完全eta擴展的定義:
foo ls x = any (>5) (map ($ x) ls)
然后將其放入您喜歡的工具中進行轉換。 http://pointfree.io/是將執行此操作的在線服務。
它吐出了完全不可讀的內容:
foo = (any (> 5) .) . flip (map . flip id)
不要使用它。 這不值得。
但是也許您只想縮小一個論點的范圍,這太多了嗎? 好吧,您可以通過作弊一點,並假裝第一個參數是作用域中的值而不是參數,然后在其中添加以下定義來做到這一點:
foo x = any (>5) (map ($ x) ls)
返回foo = any (> 5) . flip map ls . flip id
foo = any (> 5) . flip map ls . flip id
foo = any (> 5) . flip map ls . flip id
,然后將其插入回:
foo ls = any (> 5) . flip map ls . flip id
這要好一些,這要歸功於缺少(.)
運算符的各個部分。 但是它仍然具有flip id
,這是最簡單的混淆。
不要這樣 保持克制。 編寫易於閱讀和修改的代碼。
從完全非簡化的定義開始:
foo ls v = any (>5) (map (\f -> f v) ls)
我們可以使用lambdabot擁有完全減少eta的解決方案:
foo = (any (> 5) .) . flip (map . flip id)
但是,這看起來很糟糕,不建議這樣做。
其實,您在問題中的最后一次審判
foo ls = any (>5) . flip map ls ($)
已經非常接近解決方案。
唯一的問題是,考慮($)
的定義:
($)::(a -> b) -> a -> b
的第一個參數($)
是一個函數(a->b)
但在你的情況下,也可以是值a
,所以才flip ($)
交換的參數的順序($)
並把它早在:
foo ls = any (>5) . flip map ls . flip ($)
是您想要的功能。
由於您手頭有一個應用列表,因此您可以簡單地用應用運算符<*>
將其應用為[(+3), (*4), (+1)] <*> [2]
以獲取結果列表,例如作為[5,8,3]
。 現在可以使用它了any :: Foldable t => (a -> Bool) -> ta -> Bool
函數。 所以在一起
checker x = any (>5) $ [(+3), (*4), (+1)] <*> [x]
應該做的工作。 如果您需要沒有積分的版本,它將比
checker = any (>5) . ([(+3), (*4), (+1)] <*>) . pure
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.