用于确定字符串是否为回文结构的函数可以通过
以无点的应用方式实现。pal1 = (==) <$> reverse <*> id
这是一个monadic版本
reverse >>= (==)
modadic版本如何在没有显式调用id的情况下工作?我试图使用有点函数查看有针对性的表示,并获得相同的函数。
答案 0 :(得分:8)
这可以使用x -> y
可以被视为一种&#34;读者monad&#34;的事实。如果我们要说
type Reader r x = r -> x
然后我们有一个Monad (Reader r)
的实例。所以我们可以看到
reverse :: [x] -> [x]
实际上是
reverse :: Reader [x] [x]
类似地,
(==) :: [x] -> [x] -> Bool
可以写成
(==) :: [x] -> Reader [x] Bool
然后(>>=)
将两者连接在一起。
所以......我们从reverse
开始,这是一个Reader
动作,它会读取一个列表并返回一个列表。然后,我们使用>>=
将其传递给==
,这是一个获取列表的函数,并返回Reader [x] Bool
。
简而言之,输入列表由Reader
的操作复制,它基本上接受输入并将其传递给链中的每个函数。 (这就是读者monad 是。)
我希望这有点意义......我花了一段时间才弄清楚了
答案 1 :(得分:5)
让我们看一下((->) r)
的Monad实例:
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
然后只需填写你的monadic代码:
reverse >>= (==) = \r -> (==) (reverse r) r
我们可以用更熟悉的方式写作:
\r -> reverse r == r
答案 2 :(得分:4)
要添加到其他答案,这是另一个POV。让我们通过fmap
和join
来定义绑定:
m >>= act = join (fmap act m)
表达式(==) <$> reverse
的类型为Eq a => [a] -> [a] -> Bool
,相当于fmap (==) reverse
。现在,我们将其传递给join :: m (m a) -> m a
,对于(->) r
monad实例,类型将为([a] -> [a] -> Bool) -> ([a] -> Bool)
。也就是说,加入恰好是<*> id
部分。
答案 3 :(得分:1)
我认为最简单的理解方法是查看类型:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
专门针对((->) r)
实例:
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b
您没有获得a
。产生一个的唯一方法是将第一个函数r -> a
应用于您给出的r
。生成b
的唯一方法是将第二个函数应用于刚刚生成的r
和a
。这意味着此函数 * 的唯一可能定义是:
f >>= g = \a -> g (f a) a
插入我们的论据,我们得到:
reverse >>= (==)
-- definition of (>>=)
= \a -> (==) (reverse a) a
-- prefix to infix
= \a -> reverse a == a
参数化是推理多态函数的有力工具。
*除了底部
答案 4 :(得分:1)
其他答案确认两者的行为相同,但没有解释id
实际去哪里。在这个答案中,我会尝试这样做。重点是,对于Reader,我们有一个好奇的id
- 删除等式:id >>= return . f = f
。 (这个等式的一个更美丽的形式是(id >>=) = (>>= id)
;与monad定律一起,美丽的形式暗示了易于使用的形式。)使解释更简单,而不是试图从应用形式转换为monadic形式,我会理所当然地认为你相信以下等式:
(==) <$> reverse <*> id
= { too annoying to do carefully }
reverse >>= \xs -> id >>= \ys -> return ((==) xs ys)
所以我们将从最后一行开始,到reverse >>= (==)
结束。在此过程中,关键是要注意id
是(.)
的身份 - 对于Reader monad而言恰好是fmap
。我们走了:
reverse >>= \xs -> id >>= \ys -> return ((==) xs ys)
= { monad law }
reverse >>= \xs -> fmap ((==) xs) id
= { definition of fmap for Reader }
reverse >>= \xs -> (.) ((==) xs) id
= { id is the identity of fmap }
reverse >>= \xs -> (==) xs
= { eta reduction }
reverse >>= (==)
那么id >>= return . f = f
的含义是什么?那么,将函数视为“索引值”,我们可以将id
理解为等于其索引的值;和return
是各地的价值。所以id >>= return . f
说“查看索引x
;然后,(仍然在索引x
),返回忽略其索引并具有值f x
”的值。碰巧我们忽略的索引和我们交给f
的值匹配 - 所以我们也可以跳过所有的间接,简单地说“查看索引x
并应用{{1对它“。这就是等式的含义。