【问题标题】:How would I write this function in point-free style?我将如何以无点风格编写此函数?
【发布时间】:2017-08-11 09:54:34
【问题描述】:

我只是想对我的 Haskell 代码进行总体改进,并且想知道是否可以使以下函数变得无点?主要是为了好奇。

鉴于我们想在filter 中使用的两个函数:

isZero = (==0)
isOne = (==1)

我们将如何在我们设计的示例中使用这两个函数,但使其无意义?

filter (\x -> isZero x || isOne x) [0..100]

【问题讨论】:

  • 作为实例,filter ((||) <$> isZero <*> isOne) [0..100]。将(||) 提升到这样的应用函子:(<||>) = liftA2 (||)。然后使用:filter (isZero <||> isOne <||> ...) ...
  • 请注意,(||) <$> isZero <*> isOne 是 25 个字符,\x -> isZero x || isOne x 是 25 个字符。我会坚持使用有意义的版本,它更容易被人类阅读。
  • @freestyle 我爱<||>。希望它不会在其他地方使用不同的含义......
  • @Bergi 在一些包中已经定义了,例如:control-bool, classy-prelude。
  • @freestyle:我倾向于将liftA2 (||) 拼写为.||.,因为从记忆上讲,两边都有一个“点”。如果你真的很喜欢 APL 风格的默认编程,你可以添加像 (..||..) = liftA2 (liftA2 (||)) 这样愚蠢的概括,它允许像 (>=) = (>) ..||.. (==) 这样的事情(“'大于或等于'意味着'大于'或'等于'”) .

标签: haskell


【解决方案1】:

有一个online-service 用于将Haskell 代码转换为无点。

提示:filter (liftM2 (||) isZero isOne) [0..100]

liftA2 (||) isZero isOne(||) <$> isZero <*> isOne也可以

(||) <$> isZero 的类型为a0 -> Bool -> Bool,它是(||)isZero 的组合。这个组合需要一个数字(isZero)和一个布尔值(作为(||) 的另一个参数)

所以,和\x y -> (||) (isZero x) y一样

函数类型是Applicative Functor的一个实例,我们可以看看它的实现:

instance Applicative ((->) r) where  
    pure x = (\_ -> x)  
    f <*> g = \x -> f x (g x)

所以,(||) &lt;$&gt; isZero &lt;*&gt; isOne\x -&gt; ((||) &lt;$&gt; isZero) x (isOne x) 相同,与\x -&gt; (||) (isZero x) (isOne x) 相同

因此,如果有z x = y (f x) (g x),则可以转化为无点:z = y &lt;$&gt; f &lt;*&gt; g

【讨论】:

  • 这并没有解释如何扩展这个解决方案。我更喜欢@Rampion 的回答,因为它解释了如何使用liftA2 (||) 以无点风格编写任意数字谓词。
【解决方案2】:

另一种无点形式是使用a -&gt; Any monoid:

λ import Data.Monoid (Any(..))
λ :t getAny . (Any . isZero <> Any . isOne)
getAny . (Any . isZero <> Any . isOne)
  :: (Num a, Eq a) => a -> Bool
λ filter (getAny . (Any . isZero <> Any . isOne)) [0..100]
[0,1]

它比Applicative 解决方案要长一点,但我认为当你有更多的条件可以组合时,它会更容易遵循。比较

getAny . (Any . isZero <> Any . isOne <> Any . isSquare <> Any . isPrime)

getAny . foldMap (Any .) [isZero, isOne, isSquare, isPrime]

liftA2 (||) (liftA2 (||) (liftA2 (||) isZero isOne) isSquare) isPrime

liftA2 (||) isZero $ liftA2 (||) isOne $ liftA2 (||) isSquare isPrime

说实话,如果我有很多这些事情要做,我会很想定义 &lt;||&gt; = liftA2 (||) 并做

isZero <||> isOne <||> isSquare <||> isPrime

【讨论】:

    猜你喜欢
    • 2017-10-31
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2022-07-11
    • 2017-02-22
    • 1970-01-01
    相关资源
    最近更新 更多