19

多くの Pythonist から、フィルターやリデュースなどの高階関数を使用してできることはすべてできるので、リスト内包表記を好むと聞いています。では、この質問は彼らに向けたものです。HOF でできることの確かな例は何ですか? HOF では難しいことです?

4

6 に答える 6

41

答えは、そのような例はないということです。リスト内包表記でできることはすべて、機械的に高階関数に変換されます。実際、これは Haskell がリスト内包表記を実装する方法です: それはそれらを高階関数に脱糖します。

次のようなリスト内包表記があるとします。

[(x, y) | x <- [1..3], y <- [4..6]]

Haskell はそれを次のように脱糖します。

concatMap (\x -> concatMap (\y -> [(x, y)]) [4..6]) [1..3]

同様に、次のような述語を入れると:

[(x, y) | x <- [1..3], y <- [4..6], x + y /= 5]

...次に、次のように脱糖します。

concatMap (\x -> concatMap (\y -> if (x + y) == 5 then [(x, y)] else []) [4..6]) [1..3]

実際、この脱糖は Haskell 仕様の一部であり、ここで見つけることができます。

于 2013-05-28T05:13:28.060 に答える
21

すでに述べたように、リスト内包表記でできることはすべて高階関数に脱糖できますが、Python でこれを行う際の問題の大部分は、Python が使用できるポイントフリー プログラミングの種類をサポートしていないことです。filtermap、そして Haskell の仲間たち。これはやや不自然な例ですが、理解できると思います。

次の Python コードを見てみましょう。

[(x,y) for x,y in zip(xrange(20), xrange(20, 0, -1)) if x % 2 == 0 and y % 2 == 0]

これを印刷するだけです:

[(0, 20), (2, 18), (4, 16), (6, 14), (8, 12), (10, 10), (12, 8), (14, 6), (16, 4), (18, 2)]

フィルターを使用した同等のバージョンは次のとおりです。

filter(lambda ns : ns[0] % 2 == 0 and ns[1] % 2 == 0, zip(xrange(20), xrange(20, 0, -1)))

それがもっと醜いということに同意してくれることを願っています。別の関数を定義せずに見苦しくないようにするためにできることはあまりありません。

しかし、Haskell で同等のバージョンを見てみましょう:

[(x,y) | (x,y) <- zip [0..20] [20,19..0], x `mod` 2 == 0 && y `mod` 2 == 0]

わかりました、Python のリスト内包表記バージョンとほぼ同じです。同等のフィルター バージョンはどうですか?

import Data.Function
let f = (&&) `on` (==0) . (`mod` 2)
filter (uncurry f) $ zip [0..20] [20,19..0]

さて、インポートを行う必要がありましたが、コードが何をするかを理解すれば、コードは (imo) より明確にfなります。私の意見では、ポイントのないバージョンの方がより簡潔で概念的に明確です。しかし、私が言いたい主なポイントは、別のライブラリを持ち込まないと関数を部分的に適用することができず、合成演算子がないため、Python ではこれほど明確ではないということです。したがって、Pythonではマップ/フィルターよりもリスト内包表記を優先するのは良い考えですが、Haskell では、特定の問題に応じてどちらの方法でもかまいません。

于 2013-05-28T07:43:01.087 に答える
10

Haskell では、リスト内包表記は条件と関数の「構文糖衣」です (または、簡単に do 表記に変換してからモナド的に脱糖することができます)。それらを翻訳するための「公式」ガイドは次のとおりです

したがって、リスト内包表記は単に高階関数を使用して同等のコードに機械的かつ直接的に変換できるため、定義上、リスト内包表記を使用せずに行うのが難しいことは何もありません。

于 2013-05-28T05:12:53.050 に答える
1

比較

    [[x*x, x*x+x ..] | x <- [2..]]

    map (\x-> map (*x) $ enumFrom x) $ enumFrom 2

最初の方が明らかに読みやすいです。あなたは「不可能」ではなく「トリッキー」と尋ねました。また、では、特定のテストに合格または失敗した要素を でフィルタリングするか、または除外filterするかを示すものは何もありません。LC を使用すると、視覚的に明らかになります。

そのため、LC の定式化がある場合は常に、読みやすさのために、IMO が優先されます。Haskell の LC 構文は特に簡潔で明確であり、Python の IMO (ノイズが少ない) よりも明確です。それを使用しないのは残念です。:)

于 2013-05-28T12:04:14.507 に答える