用仿函数在haskell中写XOR

dav*_*vik 3 haskell boolean-logic functor applicative

我是相对较新的haskell,我刚刚学习了Applicative Functors,我只使用仿函数和布尔函数为xor创建了这个代码.我想知道你们是否可以用仿函数提出一个更短的解决方案(我确信存在).

xor :: Bool->Bool->Bool
xor=(<$>) (not<$>) ((<*>).((((not<$>)<$>(&&))<$>)<$>((not<$>)<$>(&&)))<*>(||))
Run Code Online (Sandbox Code Playgroud)

我知道这可能不是很好的做法; 对我来说这更像是一个脑筋急转弯.

PS我希望这是允许的

Dan*_*ner 9

这是一个你可以想象的手工编写的解决方案(阅读,有点指导!).正如@AJFarmar所说,我们可以写

xor a b = (a || b) && (not a || not b)
Run Code Online (Sandbox Code Playgroud)

我也将使用他所建议的改写,即a && b = not (not a || not b)尽管他做的相反:

xor a b = (a || b) && not (a && b)
Run Code Online (Sandbox Code Playgroud)

您可以按照以下过程进行其他定义,但这个定义特别短.

现在,我们可以挑选出块a || ba && b和,而不是他们的思维类型的值Bool与环境a :: Boolb :: Bool,并将其转化为我们把它们当作类型的值的形式Bool有两个Applicative"背景"的包装.因此(||) :: f (g Bool)(&&) :: f (g Bool),在fg那些特定的Applicative实例(->) Bool.所以我们处于部分翻译状态

xor = (||) && not (&&)
Run Code Online (Sandbox Code Playgroud)

现在唯一的问题是中缀&&not期望的纯Bool值,但正在被双重包裹Bool.所以我们将使用双重liftA*应用程序解除它们.从而:

xor = liftA2 (liftA2 (&&)) (||) (liftA (liftA not) (&&))
Run Code Online (Sandbox Code Playgroud)

还有其他方法来拼写这个.我喜欢的名字(<$>)liftA.此外,人们可以将双重包裹Applicative的东西视为带有更复杂包装的单独包装的东西,因此:

xor = getCompose (liftA2 (&&) (Compose (||)) (not <$> Compose (&&)))
Run Code Online (Sandbox Code Playgroud)


mel*_*ene 5

xor = (/=)
Run Code Online (Sandbox Code Playgroud)

为什么要把它变得更复杂?