Haskell +“删除参数”

时间:2014-11-07 10:27:45

标签: haskell lambda functional-programming

我有一个理论问题,一个朋友和我一直试图看,我们怎么做。我们有一个名为palindrome的函数,告诉我们String是否是回文。以下是我们实施它的方式(可能有更好的方法,但我们更喜欢它。)

palindrome :: String -> Bool
palindrome = \x -> (== reverse x) x

我们想要做的是remove我们在这里使用的Lambda,只使用部分应用程序和高阶函数。我们有几个关于如何做到这一点的想法,但它们都没有与我们制作的函数类型匹配:

palindrome :: String -> Bool

最接近的方法之一是使用合成,但它返回一个函数,它需要两个字符串而不是一个,因为一个用于反向而另一个用于(==):

palindrome = (==) . reverse

也许,我们忘记了某些事情,或者我们没有看到任何东西。为了在不使用Lambda的情况下使用这两个函数,你会怎么做?

5 个答案:

答案 0 :(得分:13)

您可以将<*>运算符用于(->)的{​​{1}}实例。

Applicative

palindrome = (==) <*> reverse 运算符在某些上下文中类似于函数应用程序。在这种情况下,该上下文是“以<*>作为参数的函数”。所以你得到一个函数,它接受String并将它传递给两个函数,这两个函数也接受String,然后将前者的结果应用于后者。换句话说,String

答案 1 :(得分:10)

你现在有三个答案,但也许没那么多理解。

问题是你右手边有两个x,它看起来不像是一个很好的删除方式一。您需要具有以下签名之一的功能才能复制&#34;那个x:

x -> (x, x)
x -> (x -> a, x -> b) -> (a, b)
((x, x) -> y) x -> y
(x -> x -> y) -> x -> y
(x -> y) -> (x -> y -> z) -> (x -> z)

这些实际上很难找到;我想象其中第一个将以dup x = (x, x)的名称提供,但它无处可寻。据我所知,在序曲中没有任何一个可以找到。

事实证明,Monad称之为&#34; Reader&#34; monad通过许多函数线程化一个值(在本例中为x)。这个monad的类型(->) x,这意味着它是所有x -> y的函数y(x -> x -> y) -> x -> y之上的倒数第二个函数实际上可以写成:

Prelude> :m + Control.Monad
Prelude Control.Monad> :t (id >>=)
(id >>=) :: (a -> a -> b) -> a -> b

因此你可以写:

id >>= (==) . reverse

或者更简洁:

palindrome = reverse >>= (==)

事实证明,其他人的版本在幕后秘密使用(>>=)。例如,每个Monad都是ApplicativeControl.Applicative库导出符号(<*>) :: Applicative f => f (x -> y) -> f x -> f y。如果f(->) a,我们会:(<*>) :: (a -> x -> y) -> (a -> x) -> y我们可以将(==)reverse应用于:{/ 1>}:

palindrome = (==) <*> reverse

Control.Monad具有相同的instance Monad ((->) x)并为其导出>>=(如上所述,(x -> y) -> (y -> x -> z) -> x -> zjoin :: m (m x) -> m x,在这种情况下为{{1} }。

有很多选项,但实例声明是在这些库中进行的。如果你想在没有这些库的情况下这样做,你就必须写出单调乏味的东西:

(x -> x -> y) -> x -> y

在应用这些功能之前。在那时,它几乎更容易编写:

instance Monad ((->) x) where
    return = const
    yx >>= zxy = \x -> zxy (yx x) x

答案 2 :(得分:8)

您可以使用join

中的Control.Monad
palindrome = join ((==) . reverse)

join是monad的基本功能。但是,对于这种特殊情况,即功能(或更准确地说,是(->)的{​​{1}}实例),Monad只评估为join f x

答案 3 :(得分:4)

还有一些替代方案(虽然比以前的答案更差; - ))

import Control.Arrow
palindrome1 = (reverse &&& id) >>> uncurry (==)
palindrome2 = ((==) &&& reverse) >>> uncurry ($)

答案 4 :(得分:2)

使用Control.Applicative

palindrome = (==) <*> reverse