4

私は最近 Haskell を学び始めたばかりで、より具体的には、関数合成、部分関数、マップ、フィルター、およびセクション化のトピックについてです。演習の 1 つで、twoFilters関数合成を使用して関数を変更するよう求められます。

いくつかのウィキを読んだことがありますが、.正しく動作させるのにかなり苦労しています。私が理解しているように、b . aアルファベット順に関数を実行し、結果を返すことで機能します。つまりx = foo a、そしてfoo b of x. ただし、次の2つのフィルター関数を使用していくつかの「バリエーション/可能性」を適用した後、エラーのためにコンパイルできません。

greaterThanOne :: Int -> Bool
greaterThanOne = (>1)

lessThanTen :: Int -> Bool
lessThanTen = (<10)

twoFilters :: [Int] -> [Int]
twoFilters xs= filter lessThanTen (filter greaterThanOne xs)

これらの 2 つは、私が最も自信を持っていた失敗した試みです。

twoFilters xs = filter (lessThanTen . greaterThanOne xs)

twoFilters xs = filter (lessThanTen xs . greaterThanOne xs)

推論のどこが間違っているのでしょうか?

4

7 に答える 7

3

あなたが自信を持っていた試みは、ロジックの単純な失敗です。ドット演算子は次のように機能します。

(f.g)(x) = f(g(x))

したがって、5の例を計算しようとすると、次のようになります。

lessThanThen(greaterThanOne(5)) = lessThanTen(True) -- that can't be right, can it???

必要なのはラムダと&&です:

filter (\x-> (lessThanThen x) && greaterThanOne(x))

または、次の2つのフィルターを使用できます。

filter lessThanTen . filter greaterThanOne $

于 2011-02-20T15:31:13.127 に答える
3

Applicative Functor の素晴らしい世界に入りましょう:

import Control.Applicative

greaterThanOne = (>1)

lessThanTen = (<10)

twoFilters = filter ((&&) <$> greaterThanOne <*> lessThanTen)

twoFilters [1,2,3,4,5,6,7,8,9,10]
-- [2,3,4,5,6,7,8,9]

詳細な説明については、Haskell の学習 - Applicative Functorを参照してください。

于 2011-02-20T16:18:45.550 に答える
2

このように2つの機能を構成することはできません。f . g数学の合成のように機能します。つまり、と同等f(g(x))です。つまり、外部関数は、内部関数が返す型の引数を取る必要があります。この場合、外部関数はである必要がありますBool -> Bool

twoFilters次のように、 using合成演算子を記述できます。

twoFilters = (filter lessThanTen) . (filter greaterThanOne)
于 2011-02-20T15:31:13.970 に答える
1

あなたはそれをほぼ正しいと思います。関数合成の学習を始める最も簡単な方法は、代わりに最初に.使用することです。$

だからあなたはリストを持っています

twoFilters xs = xs

フィルタリングしたいgreaterThanOne

twoFilters xs = filter greaterThanOne $ xs

さらに、でフィルタリングしたいlessThanTen

twoFilters xs = filter lessThanTen $ filter greaterThanOne $ xs

次に、左から右に移動し、最後$を除くすべてのを置き換えます.$

twoFilters xs = filter lessThanTen . filter greaterThanOne $ xs

今の代わりに括弧を使用することができます$

twoFilters xs = (filter lessThanTen . filter greaterThanOne) xs

または、関数pointfreeを定義するだけです。

twoFilters = filter lessThanTen . filter greaterThanOne

括弧で囲まれたバージョンが最も重要だと思います。filter lessThanTenこれは、2つの部分的に適用された関数をfilter greaterThanOne1つのメガフィルタリング関数に融合し.次にリストをそれに適用することを示しています。空白を介した関数適用よりも緊密にバインドされないため、括弧で囲む必要があり.ます(スペースはの超高固定バージョンと見なすことができます$)。.を使用する場合、2つの関数を融合して1つのメガ関数を形成していることを忘れないでください。

の型署名を検査することは適切です.

(.) :: (b -> c) -> (a -> b) -> a -> c

フィードする関数は、非常に特定の型アノテーションと「整列」する必要があります(融合と互換性がある必要があります)。しかし正直なところ、重要なのは、関数適用(スペースあり)が意図したよりも緊密にバインドされていることを認識し、作成しようとしている関数の型アノテーションを台無しにすることです。とにかく、それが私にとってのやり方でした。

于 2011-02-20T17:27:59.417 に答える
1

(.)1つの引数を取り、値を返す関数が必要ですが、次の場所にBool値を渡します。

lessThanTen . greaterThanOne xs

これは間違っています。

ここ:

lessThanTen xs . greaterThanOne xs

2つの値を作成しようとしてBoolいますが、値を返す2つの関数を作成する必要がありBoolます。

于 2011-02-20T15:30:50.273 に答える
1

1 つの問題として、関数の適用が最も優先されます。そのため、の結果でlessThanTen . greaterThanOne xs構成しようとします(これは最初は機能しません。関数は整数のリストではなく整数で機能します)。同様に、関数自体ではなく、これらの関数呼び出しの結果を構成しようとします (そもそも意味があると仮定して)。lessThanTengreaterThanOne xslessThanTen xs. greaterThanOne xs

もう 1 つの問題は、.-(f . g) xが と等価であるという誤解ですf (g x)。つまり、最初の関数の結果が 2 番目の関数の引数になります。したがって、の型はあるg必要が(a -> b)あり、の型はあるf必要があります(b -> c)(両方ともb同じ型変数です!)。両方の関数を同じ引数に適用し、結果を で結合したいもの&&。私の知る限り、これに対する既存の関数はありません (少なくとも Hoogle は に対して何も見つけられませんでした(a -> Bool) -> (a -> Bool) -> a -> Bool)。自分で作成する必要があります:

both f g x = f x && g x

または、2 回フィルタリングすることに固執することもできます (遅延評価のおかげで、思ったほど悪くはありません) - filter (>1) $ filter (<10) xs.

于 2011-02-20T15:33:47.837 に答える
1

私が理解しているように、b . aアルファベット順に関数を実行し、結果を返すことで機能します。つまりx = foo aその後foo b of x

これは、Haskell で次のように記述できます。

let x = foo a in 
foo b x

(どこfooから来たの?)しかし、正しい

(b . a) x = let y = a x in
            b y

または、より短い:

(b . a) x = b (a x)

さて、filter lessThanTen (filter greaterThanOne xs)この定義の右側に似た形をしています。覚えていれば、次のように書くことができます(filter lessThanTen) ((filter greaterThanOne) xs)

((filter lessThanTen) . (filter greaterThanOne)) xs

おそらく、あなたが実際に望んでいるfilter ??? xsのは ですが、それで十分です。

于 2011-02-20T15:38:48.810 に答える