我有一个理论问题,一个朋友和我一直试图看,我们怎么做。我们有一个名为palindrome
的函数,告诉我们String是否是回文。以下是我们实施它的方式(可能有更好的方法,但我们更喜欢它。)
palindrome :: String -> Bool
palindrome = \x -> (== reverse x) x
我们想要做的是remove
我们在这里使用的Lambda,只使用部分应用程序和高阶函数。我们有几个关于如何做到这一点的想法,但它们都没有与我们制作的函数类型匹配:
palindrome :: String -> Bool
最接近的方法之一是使用合成,但它返回一个函数,它需要两个字符串而不是一个,因为一个用于反向而另一个用于(==):
palindrome = (==) . reverse
也许,我们忘记了某些事情,或者我们没有看到任何东西。为了在不使用Lambda的情况下使用这两个函数,你会怎么做?
答案 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
都是Applicative
,Control.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 -> z
和join :: 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