怎么样[[(x !! 0,x !! 1)|x<-mapM(const ['A','B','C'])[1..2],头x<head(tail x)]`work? [英] How does `[ (x !! 0, x !! 1) | x <- mapM (const ['A', 'B', 'C'] ) [1..2], head x < head (tail x) ]` work?

查看:38
本文介绍了怎么样[[(x !! 0,x !! 1)|x<-mapM(const ['A','B','C'])[1..2],头x<head(tail x)]`work?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Haskell的新手,想知道语句如何

I am new to Haskell and wondering how the statement

[ (x !! 0, x !! 1) | x <- mapM (const ['A', 'B', 'C'] ) [1..2], head x < head (tail x) ]

有效.(我在StackOverflow上找到了它.)我知道它的输出,但是我并不是很了解.

works. (I found it on StackOverflow.) I know what it outputs, but I am not really understanding it.

推荐答案

好吧,以上表达式可能不是惯用 Haskell.更好的版本可能是:

Well the above expression is likely not what is considered idiomatic Haskell. Probably a better version would be:

[ (x0, x1) | (x0:x1:_) <- mapM (const "ABC") [1..2], x0 < x1 ]

这是更干净的方法,如果 mapM(常量"ABC")中的列表将返回包含少于两个元素的列表(在此是不可能的),则不会出错.

This is cleaner and if the lists in the mapM (const "ABC") would return a list that contains less than two elements (that is here impossible), it will not error.

这里的核心问题可能是了解 mapM 的工作方式.表达式 mapM(const"ABC")[1..2] 可以归结为:

Probably the core problem here is to understand how mapM works. The expression mapM (const "ABC") [1..2] boils down to:

mapM (\_ -> "ABC") [1..2]

因为我们没有考虑列表的值,所以它等效于:

since we do not take the values of the list into account, it is equivalent to:

replicateM 2 "ABC"

2 replicateM 可以重写为(伪Haskell语法):

This replicateM for 2 can be rewritten as (pseudo-Haskell syntax):

replicateM 2 :: [a] -< [[a]]
replicateM 2 l = do
    x0 <- l
    x1 <- l
    return [x0, x1]

或者如果我们对此加糖:

or if we desugar this:

replicateM 2 l = l >>= \x0 -> l >>= \x1 -> return [x0, x1]

对于列表, Monad 的实例实现为:

For a list, the instance of Monad is implemented as:

instance Monad [] where
    return x = [x]
    (>>=) = flip concatMap

因此,对于列表来说,此 replicateM 2 被实现为:

so that means that for a list this replicateM 2, is implemented as:

replicateM 2 l :: [a] -> [[a]]
replicateM 2 l = concatMap (\x0 -> concatMap (\x1 -> [[x0, x1]]) l) l

或更简单:

replicateM 2 l :: [a] -> [[a]]
replicateM 2 l = concatMap (\x0 -> map (\x1 -> [x0, x1]) l) l

因此,我们将列表的两个项目组合为所有可能的组合.因此,这意味着:

we thus make all possible combinations of two items of the list. This thus means that:

Prelude Control.Monad> replicateM 2 "ABC"
["AA","AB","AC","BA","BB","BC","CA","CB","CC"]

然后在列表理解中使用此方法,对于每个具有两个元素的子列表,我们检查第一个元素 x0 是否小于带有 filter部分的第二个元素在列表推导中( x0< x1 ).如果是这样,我们将这些元素生成为2元组.

We then use this in list comprehension, and for each of these sublists with two elements, we check if the first element x0 is smaller than the second element with the filter part in the list comprehension (x0 < x1). If that is the case, we yield these elements as a 2-tuple.

因此,如果第一个元素(严格)小于第二个元素,则为"ABC" 中的每两个元素创建2个元组.

It thus creates 2-tuples for each two items in "ABC", if the first element is (strictly) smaller than the second one.

但是,我们在这里做了一些太多的工作":一半以上的元素将被拒绝.我们可以通过使用 tails :: [a]->[[a]] :

Here we however do a bit "too much work": more than half of the elements will be rejected. We can optimize this by making use of tails :: [a] -> [[a]]:

import Data.List(tails)

[(x0, x1) | (x0:xs) <- tails "ABC", x1 <- xs ]

产生相同的值:

Prelude Control.Monad Data.List> [(x0, x1) | (x0:xs) <- tails "ABC", x1 <- xs ]
[('A','B'),('A','C'),('B','C')]

这篇关于怎么样[[(x !! 0,x !! 1)|x&lt;-mapM(const ['A','B','C'])[1..2],头x&lt;head(tail x)]`work?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆