2016-12-04 6 views
1

私はシンプルな機能を持っており、ポイントフリーのスタイルを意識したいと思っています。この再帰関数をポイントフリーにすることはできますか?

shout :: String -> String 
shout input 
    | null input = [] 
    | otherwise = (toUpper . head $ input) : (shout . tail $ input) 

私の直感は

コンスセルの最初の引数が期待されるタイプ「文字列と一致しない可能性があるため、次の文句を言っているこの

pfShout :: String -> String 
pfShout = (toUpper . head) : (shout . tail) 

に私を導きました - >文字列 ' 実際の型' [[Char] - > Char] '

  • 考えられる原因:多すぎる引数に '(:)'が適用されます

    式の(toUpper。ヘッド): 'pfShout' の式(pfShout尾)

    : pfShout =(TOUPPERヘッド):(pfShout尾)

及び第二のために、この不満短所の引数は、セル

予想と一致しませんでしタイプ '[[シャア] - >チャー]' 実際の型と '[シャア] - >文字列'

  • 考えられる原因は: '(。)' '(:)'、すなわち「(pfShoutの第2引数での少なすぎる引数

    適用されます。 pfShout =(TOUPPERヘッド):(pfShout尾)

  • pfShout '「のための式(pfShout尾)

    式において

    。:(TOUPPER頭)。' 尾部) 「[ - >チャー[シャア]]」、と私は得るために始めている機能 - 「>文字列文字列」

それは私が外のリストを作ることができないことを私に明らかです私が思っている場所には、これはちょうどポイントフリーでは動作しません。

私はここに他の考慮事項があることを理解しています(今はベースケースがないようですが)。私はまた、私は完全に同じ効果(map toUpperのような)を達成するために関数を書き直すことができることを理解しています。私は主に、ポイントフリーのに、再帰関数を書かれているように使って興味を持っています。

この関数をポイントフリーで書くことができない場合は、何が欠けていますか?

+5

は '叫ぶ=地図toUpper'の仕事でしょうか? –

+0

ああ、完全に調整する方法は間違いありませんが、再帰的なバージョンポイントを自由にできるかどうかは疑問でした。これを入力すると「再帰がポイントフリーではないのかもしれません」と思っています。 – Matt

+0

'(toUpper。head):(shout。tail)'を修正することができたとします(可能です)。どのように再帰が終了するのですか?あなたはいくつかの状態を評価する必要があります。どのようにポイントフリーの状態で条件を書いていますか? –

答えて

7

@ n.mには、shout = map toUpperを使用できます。しかし、mapfoldrのような他の機能を使わなくても可能ですが、より多くのコンビネータが必要です。入力引数をとり、それを2つの関数toUpper . headshout . tailに渡して、それを:と組み合わせるものが必要です。あなたはpropablyまだこの機能を知らないが、応用的から<*>オペレータは、私たちが必要とするものがあります。

(f <*> g) x = f x (g x) 

今、私たちはこのような何かを行うことができます。

combine . f <*> g = \x -> combine (f x) (g x) -- [1] 

私はあなたがどのように把握できるようになりますあなたの問題にこれを適用すること。 ;)

しかし、何とか空のリストケースを表現する必要があります。これを行うには複数の方法がありますが、最も簡単なのは、ifの機能と同様のData.Bool機能からのboolの機能とjoinControl.Monadです。

-- [2] 
bool x _ False = x 
bool _ x True = x 

join f x = f x x 

今、私たちは、次の操作を実行できます。

shout = join $ bool (not null case) (null case) . null 
-- Which translates to 
shout xs = bool ((not null case) xs) ((null case) xs) (null xs) 

は再び2例を実装読者に運動して残されています。

[1]:代わりに(.)のあなたはまた、機能のために(.)が、(<$>)(<*>)と同じである(<$>)は一種の一緒に属して使用することができます。なぜあなたは一度応募書類を学ぶのか理解できます。

[2]:

data Bool = False | True 

そして、この順序が動機付けられている:あなたはboolの引数の順序の背後にある理由は、最初の引数が何であるか疑問に思う場合Boolは、次のように定義されているためFalse場合であります大会の内容はFalse < Trueです。 maybeeitherは、この正確なパターンをboolと共有する2つの他の関数です。

+0

申し訳ありませんが、私はまだいくつかの章を私の本に見ています。非常に徹底的な返答をありがとう! – Matt

+0

'Applicative'の場合は機能しますか?私はこれらの行に沿って答えを出していましたが、タイプチェックをすることはできません。 'shout =(:) <$>(toUpper.head)<*>(shout。tail) 'は"少なくとも "無限リストのために"動作しますが、これを 'bool'と組み合わせると型エラーが発生します。 'shout = bool((:) <$>(toupper。head)<*>(叫んで尾))id。 「ヌル」。 – chepner

+0

@chepnerあなたはちょうど 'join'がありません。 'bool'は述語の引数を消費し、2つの場合の関数を適用するものは何もありません。 – jpath

2

ポイントフリースタイルのものを書き換えるには、pointfreeをインストールするか、オンラインバージョン(http://pointfree.ioまたはhttps://blunt.herokuapp.com)のいずれかを使用してください。

あなたの表現

\input -> (toUpper . head $ input) : (shout . tail $ input) 

は(あなたは、彼らがこのような場合には互換性があり、apため<*>を置き換えることができます)

ap ((:) . toUpper . head) (shout . tail) 

に変換されます。

しかしこれでは不十分です。あなたは何とか再帰を終了する必要があります。 pointfreeスタイルでこれを行うには、無料でifまたはHaskellに存在しないような点滅のパターンマッチが必要です。理論上、ifは組み込み関数として定義することができますが、これはポイントフリーの定義を可能にしますが、ハスケルではそうではありません。 (一つは、このような関数を定義することができますが、その実装はpointfreeではないでしょう。あなたがData.Bool.boolためmapを取引することができますので、しかし、ポイントはありますか?.$とさえapなどの

コンビネータはおそらく内部のいずれかpointfreeされていませんが、それらを使用して感じては不正行為のようです。彼らは機能を扱うだけなので、boolまたはmapよりも何らかの根本的な感じがします。

関連する問題