2015-12-30 9 views
5

私はちょうどhaskellの簡単な演習を行っていますが、if-then-else文をMaybeの型に変換するポイントフリーの方法があるかどうか疑問に思っていました。条件がfalseの場合はNothingが返され、入力がJustの場合条件が真である場合。要するに条件付きチェックを入力の多分型に変換するポイントフリーの方法はありますか?

、いくつかの与えられた:

maybeIf :: (a -> Bool) -> a -> Maybe a 
maybeIf cond a = if cond a then Just a else Nothing 

aに対して点フリーで実装がありますか?私はさらに具体的なバージョンa -> Maybe aを見ていて、Control.Arrowのどこかに答えがあるように感じます。しかし、Maybeはデータ型であり、if-else文がデータフローを制御するので、綺麗なやり方があるかどうかはわかりません。

答えて

7

あなたはData.Foldableからfindをインポートすることができますし、それは非常に単純です:あなたは非常に簡単に定義することができるように機能findが複雑ではありません

import Data.Foldable(find) 

maybeIf cond = find cond . Just 

それはMaybeの点で、一般的にそれほど一般的ではありませんが、実際には自分の実装であるmaybeIfとはまったく異なるので、なぜそれをやりたかったのかによってはあまり得られないかもしれません。

6

そのポイントを無駄にする方法は、if/then/elseです。あなたはif'コンビネータを定義することもできますし、私が定義し、この一般化バージョンを使用し、頻繁に使用することができます:私は本当にないものの

ensure p x = x <$ guard (p x) 

標準ツールが

ensure p = ap (<$) (guard . p) 
ensure = ap (<$) . (guard .) 

として連続ポイントフリー版を与えますどちらかがポイントのあるバージョンよりも優れていると思う。

+2

'Data.Bool'には' bool'があります。 – dfeuer

+1

非常に興味深い!私は単純で簡潔な方法で学ぶことが最も重要なので、私はこの答えが一番好きだと思います。私は彼の答えが最も読みやすいので@Peterにこれを与えるつもりです。私はポイントフリーのwrtを求めていたと思います。 – stites

3

我々は...

truth :: Bool -> a -> a -> a 
truth True t f = t 
truth False t f = f 

をブールのための教会エンコードを選択した場合はその後、我々はApplicativeのスタイルでポイントのないmaybeIfを書くことができます。

maybeIf :: (a -> Bool) -> a -> Maybe a 
maybeIf = liftA3 truth <*> pure Just <*> pure (pure Nothing) 

いくつかの直感...ここ

f <$> m₁ <*> … <*> mₙ = \x -> f (m₁ x) … (mₙ x) 
liftAₙ f <$> m₁ <*> … <*> mₙ = \x -> f <$> m₁ x <*> … <*> mₙ x 

は場合にインストールしたフォントが必要なUnicode文字をサポートしていない、上記の「直感」のPNG形式のレンダリングです。

enter image description here

したがって:

liftA3 truth <*> pure Just <*> pure (pure Nothing) 
= liftA3 truth <$> id <*> pure Just <*> pure (pure Nothing) 
= \p -> truth <$> id p <*> (pure Just) p <*> (pure (pure Nothing)) p 
= \p -> truth <$> p <*> Just <*> pure Nothing 
= \p -> \a -> truth (p a) (Just a) ((pure Nothing) a) 
= \p -> \a -> truth (p a) (Just a) Nothing 
+0

私はいくつかの文字を見ることができません! 「いくつかの直感」の後に、「1」でないコードブロックの添え字(?)は四角い疑問符です。 – stites

+1

@stites見ることができるはずのレンダリングを追加しました。 – erisco

2

dfeuer's leadに続いて(この機能のためにダニエル・ワーグナーの新しい名前を使用して)、

import Data.Bool (bool) 
--   F T  
-- bool :: a -> a -> Bool -> a 

ensure :: (a -> Bool) -> a -> Maybe a 
ensure p x = bool (const Nothing) Just (p x) x 

ensure p = join (bool (const Nothing) Just . p) 
      = bool (const Nothing) Just =<< p 

ensure  = (bool (const Nothing) Just =<<) 

joinはモナド関数で、join :: Monad m => m (m a) -> m aですが、機能のために、それは単にとして受け入れられている

join k x = k x x 
(k =<< f) x = k (f x) x 

joinですポイントフリーコードのW combinatorの代わり。

実際

  = join ((bool (const Nothing) Just .) p) 
      = (join . (bool (const Nothing) Just .)) p 

として、(結果の可読性は全く別の問題である)あなたは、それがポイントのない値の引数に関してたかったが、それはさらに joinで式を変換するのは簡単です
#> (join . (bool (const Nothing) Just .)) even 3 
Nothing 

#> (bool (const Nothing) Just =<<) even 4 
Just 4 
+1

@dfeuer私は編集しました、ありがとうございます。結果として得られる表現は目立ちませんが、少なくとも今はポイントフリーです。 –

+1

Hm ....一般化 'p = join(bool(const empty)pure。p)'には意味があるのだろうかと思います。 – dfeuer

+0

@dfeuer nice!それはもっとはっきりしています...そして、新しいベースでこれはDaniel Wagnerの優れた '(<$) <*>ガード' p''、 '' guard :: Alternative f => Bool-> f() ''(http ://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:guard)!(つまりMonadPlusではない) –

関連する問題