2011-02-09 3 views
31

私は比較的新しいHaskellで、 "Real World Haskell"を読み始めました。私はちょうどタイプを見つけました。たぶん、例えば「ちょうど1」から実際の値を受け取る方法についての質問があるかもしれません。私は、次のコードを書かれている:Haskellの "価値"を得る方法

combine (Just 1) Nothing (Just 2) 

をしかし、私は変更する場合、例えば、1列に、それは動作しません。これは私が使用している場合は正常に動作

combine a b c = (eliminate a, eliminate b, eliminate c) 
       where eliminate (Just a) = a 
         eliminate Nothing = 0 

。 私は理由を知っていると思います:eliminateは1つのタイプを返さなければならないので、この場合はIntです。しかし、どうすればeliminateを少なくとも文字列で処理するように変更できますか? (または多分種類のすべての種類と?)

+0

文字列を返すことを期待するなら、 'Nothing'の応答はどうでしょうか? –

+9

あなたは、すべてのタイプについて「結果なし」を示すために使用できるトークンを探しています...それはまさにNothingです。 'Nothing'を' a'に変換する統一的な方法がないので、 'abe - a 'という総和関数はありません。あなたができる最善のことは、 ''おそらく、おそらくb、おそらくc) - >たぶん(a、b、c) ' –

+0

の可能な複製を書くことです。 http://stackoverflow.com/questions/3375483/operating-on-a-return-from-a-maybe-that-c​​ontains-just) –

答えて

24

これは不必要に長い答えであり、私はなぜそれが受け入れられたのか分からない。最も高いupvoted答えに示唆されるようにmaybeまたはData.Maybe.fromMaybeを使用してください。それに続くのは、実用的なアドバイスではなく、もっと多くの思考実験です。

これで、さまざまな種類の機能を持つ関数を作成しようとしています。これはクラスを作る良い時期です。 JavaやC++でプログラミングしたことがあるなら、Haskellのクラスはそれらの言語のようなものです。

class Nothingish a where 
    nada :: a 

このクラスはNothingのクラスの同等であると想定される値nadaを、定義します。今、楽しい部分:このクラスのインスタンスを作る!タイプMaybe aの値については

instance Nothingish (Maybe a) where 
    nada = Nothing 

、何もないような値は、よく、Nothingです!これは1分で奇妙な例になるでしょう。しかしその前に、このクラスのインスタンスもリストにしましょう。

instance Nothingish [a] where 
    nada = [] 

空のリストはNothingのようなものですよね?したがって、String(Charのリスト)の場合、空の文字列""が返されます。

数値も簡単に実装できます。あなたはすでに0が数字の「無し」を表していることを示しています。

instance (Num a) => Nothingish a where 
    nada = 0 

あなたはファイルの先頭

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-} 

それともあなたはそれをコンパイルするときに、これらの言語プラグマのフラグを設定することが可能で、特別なラインを入れない限り、この1つは実際には動作しません。彼らを心配することはなく、もっと魔法を使うだけです。

今、あなたはこのクラスとそのインスタンスを持っています...今、それらを使用する関数を書き直しましょう!

eliminate :: (Nothingish a) => Maybe a -> a 
eliminate (Just a) = a 
eliminate Nothing = nada 

お知らせ私だけnada0を変更し、残りは同じです。それをスピンアップしよう!

ghci> eliminate (Just 2) 
2 
ghci> eliminate (Just "foo") 
"foo" 
ghci> eliminate (Just (Just 3)) 
Just 3 
ghci> eliminate (Just Nothing) 
Nothing 
ghci> :t eliminate 
eliminate :: (Nothingish t) => Maybe t -> t 
ghci> eliminate Nothing 
error! blah blah blah...**Ambiguous type variable** 

価値観に適しています。 (ちょうど何もない)がNothingに変わったことに気づく。それは奇妙な例だったかもしれません。とにかく... eliminate Nothingについてはどうですか?結果の型はあいまいです。私たちが期待していることは分かりません。だから、私たちはどのようなタイプを望んでいるのかを伝える必要があります

ghci> eliminate Nothing :: Int 
0 

他のタイプのものを試してみてください。それぞれについてnadaが得られることがわかります。だから今、あなたはあなたのcombine機能で、この機能を使用する場合、あなたはこの取得:

ghci> let combine a b c = (eliminate a, eliminate b, eliminate c) 
ghci> combine (Just 2) (Just "foo") (Just (Just 3)) 
(2,"foo",Just 3) 
ghci> combine (Just 2) Nothing (Just 4) 
error! blah blah Ambiguous Type blah blah 

をあなたはまだ「何も」と入力しないものを示すために持っている通知はある、またはあなたが何を期待戻り値の型を示しています。

ghci> combine (Just 2) (Nothing :: Maybe Int) (Just 4) 
(2,0,4) 
ghci> combine (Just 2) Nothing (Just 4) :: (Int, Int, Int) 
(2,0,4) 

または、タイプシグネチャを明示的にソースに入れることで、関数の種類を制限することができます。これは、関数の論理的な使用が、同じ型のパラメーターでのみ使用されるということであれば理にかなっています。

combine :: (Nothingish a) => Maybe a -> Maybe a -> Maybe a -> (a,a,a) 
combine a b c = (eliminate a, eliminate b, eliminate c) 

3つのすべてのものが同じタイプの場合にのみ機能します。そうすれば、Nothingは他のタイプと同じタイプであると推測されます。

ghci> combine (Just 2) Nothing (Just 4) 
(2,0,4) 

曖昧さはありません。しかし今は前と同じようにミックスしてマッチさせるのは誤りです。

ghci> combine (Just 2) (Just "foo") (Just (Just 3)) 
error! blah blah Couldn't match expected type blah blah 
blah blah blah against inferred type   blah blah 

まあ、私はそれが十分に長く、過度の答えだったと思います。楽しい。

+0

また、新しい関数はMaybeでラップされた 'Nothinglike'型のインスタンスに対してのみ機能します。しかし、型が 'Nothinglike'でなければ、なぜ、最初に' Nothing'の入力が与えられたときに、この型の値を生成すると思いますか?;) –

+1

初心者のための新しいものがたくさんあります;)このような小さな問題を解決するのが難しい場合は、私はあなたの解決策を理解し、この言語を勉強することについて真剣に疑念を抱いています。しかし、ええ、私は時間を取って、いくつかの例を行い、それが私に合っているかどうかを決めるでしょう)(最後にちょっと疑問があるなら、消去はストリングと整数だけで動作するはずです。 0?) – Moe

+0

@Moeの問題は、Haskellでは、複数の型で動作するメソッドを作るのは難しいが、すべての型では動作しないということです。だから、そのトリックは、特定の種類のクラスで動作させることです。 RWHを読んだままにしておけば、このすべてのことは間もなく明白になるはずです。 –

38

デフォルト値、および機能を考えると、標準Prelude

maybe :: b -> (a -> b) -> Maybe a -> b 
maybe n _ Nothing = n 
maybe _ f (Just x) = f x 

から、Maybeの値に関数を適用するか、デフォルト値を返します。

eliminateは、maybe 0 idと書くことができます。 関数とは対照的に、これは、部分機能は、すべての入力の値を返さない(ある

fromJust :: Maybe a -> a 
fromJust Nothing = error "Maybe.fromJust: Nothing" 
fromJust (Just x) = x 

、恒等関数を適用する、または標準Data.Maybeから0

を返しますこれは可能ですが、可能であれば値を抽出します。

+6

「maybe」の代わりに、 'Data.Maybe.fromMaybe :: a - >おそらくa-> a'を使用してください。 –

+0

@John nice。私の答えの文脈では、 'elimin = fromMaybe nada'と書くことができます –

+0

ただ私の問題を解決しました! – user9589

1

これはかなり明白です。 「排除」関数の型シグネチャがある:それは仮定するコンパイラを強制的に、何もに0を返すためです

eliminate :: Maybe Int -> Int 

そのあなたの「排除」機能で「:: INT」。

combine :: Maybe Int -> Maybe Int -> Maybe Int -> (Int, Int, Int) 

を、あなたはそれに文字列を渡すとき、それは動作しない理由は正確です:したがって、コンパイラは「組み合わせ」機能の型シグネチャがあることを推測します。

あなたのようにそれを書いた場合:

combine a b c = (eliminate a, eliminate b, eliminate c) 
       where eliminate (Just a) = a 
         eliminate Nothing = undefined 

それは文字列で、または任意の他のタイプで働いているだろう。その理由は、 "undefined :: a"が多型を排除し、Int以外の型に適用できるという事実に依存します。

もちろん、これはコードの目的ではなく、つまり結合機能を合計することです。

実際に、いくつかのNothing引数に "結合"するアプリケーションが成功したとしても(これはHaskellがデフォルトで怠惰だからです)、結果を評価しようとすると実行時エラーが "undefined"有用なもの(単純な言葉で言えば)に評価することはできません。

+0

@Christianoあなたの答えに感謝します。私はすでに考えている私の質問で述べたように、コンパイラが戻り値の型を整数にすることを強制するのは0かもしれません。しかしそれは私の問題で私を助けません。どのように3つの多分型を取る関数を、haskellに書くことができますか?値は、maybesの値ですか、それとも何もないなら、tupelを返しますか? – Moe

+1

MaybesでInt以外の値を渡す予定がある場合は、できません。私はこれが最初にイライラするかもしれませんが、それについて考えてみてください:それは役に立ちますか?結合の結果を消費する関数を想像できますか?それはどのような特徴がありますか? –

2

私はハスケルにも新しくなっているので、これがまだプラットフォームに存在するかどうかはわかりませんが(私はそうするでしょう)、値を得るための "getまたはelse"関数はどうでしょうか?それ以外の場合はデフォルトを返しますか?

getOrElse::Maybe a -> a -> a 
getOrElse (Just v) d = v 
getOrElse Nothing d = d 
+5

'fromMaybe' http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Maybe.html#v:fromMaybe – raine

関連する問題