2012-12-30 11 views
5
toFloat :: (Floating a) => String -> a 
toFloat s = read s :: Float 

main = print (toFloat "1") 

は私にエラーを与える:Haskellの型クラス(?フロートがフローティング意味するものではありません)

Could not deduce (a ~ Float) 
from the context (Floating a) 

私は基本的な何かが欠けていると確信しているが、私のtoFloatは常にフロートを返す必要がありますようにそれはそうフロートは浮動を意味するはずです。

答えて

18

型シグネチャは、発信者が望んでいるFloatingクラスの任意のインスタンスになります結果をお約束のようなものをすれば何が起こるかを理解することができます。実装は「何を知っているのですか?それはどのタイプにもなることを約束してはいけません - それをFloatにする」と言います。

コンパイラが来て、「うわあ!あなたが約束したタイプを返さない」と言っています。それを除いて、あなたのタイプシグネチャを作成し、実装が一致することを本当に難しくしました。 「これが何とか制約されていると、aはいつもFloatと同じだったとすれば、これは正しいでしょう。あなたのコードが正しい方法を見つけたかったのです。そのような制約を書く方法は、タイプ平等演算子~を使用しています。 (a ~ Float)という制約は、「aFloatと同じタイプです」を意味します。したがって、コンパイラは型シグネチャで指定したコンテキストをチェックし、その制約を見つけることができません。また、型シグネチャと実装が連携して動作しなくなり、あきらめてエラーを報告します。

残念ながら、報告されたエラーは、コードを動作させるためにどれほどの努力を払うかによって少し不透明です。わずかな制約を加えたほんの少しの変更で、それが正しいものになっていたでしょう。したがって、その制約は存在しないと報告しています。しかし、あなたが以前にそれを見ていないならば、それがその制約を探していた理由を報告せず、すべてを少し不明瞭にしています。

+0

クイック応答ありがとう。これは私の問題を完全に明確にします。どういうわけか、私の関数の呼び出し元が私のtypeclassの特定のインスタンスを要求できるということは私をクリックしませんでした。 – nottombrown

5

toFloatFloatingタイプキャストに属するタイプを返すことができますが、それはFloatに限定されていますが間違っています。あなたの関数はaのポリモーフィックなので、Floatingのインスタンスを返すことはできません。すべてのインスタンスで動作するはずです。

OtherwayあなたはでそれがFloatingを型クラスに属するタイプを返しますので、あなたは(Floatingに属する)任意の型に変換することができるはずGHCiの

*Main> :t toFloat "12.1" 
toFloat "12.1" :: (Floating a, Read a) => a 
*Main> :t (toFloat "12.1" :: Float) 
(toFloat "12.1" :: Float) :: Float 
*Main> :t (toFloat "12.1" :: Double) 
(toFloat "12.1" :: Double) :: Double 

toFloat :: (Read a,Floating a) => String -> a 
toFloat s = read s 

ことで、これを理解することができます関数が適用された後に明示的な型シグネチャを提供する。 一方、Floatを明示的に返すときは、この関数からDoubleを期待しているとは言えません。

あなたの仮定が今ここに機能read

read :: Read a => String -> a 

を考えるあなたに応じて、あなただけのIntReadのインスタンスを持っているので、すべてのためにIntを言う返すことができているか恐ろしい。理解する別の方法今あなたが

read "12" + (1.2 :: Double) 
1

これは、あなたがそれを持っている可能性と同じくらい簡単です:

-- The simplest.                                    
toFloat :: String -> Float 
toFloat = read 

-- More generalized.                                   
toFloat' :: (Floating a, Read a) => String -> a 
toFloat' = read 
8

この質問またはそれに非常に類似したものは、定期的に尋ねます。

OO言語では、「この関数はXを実装するものを返します」と言い換えることができます。これは苦情ではありません。関数は返すような気持ちを返すことができます。は、実際にはXを実装している限り、です。

ハスケルはそのようには動作しません。 「この関数がXを実装するものを返す」と言うと、その関数はXを実装するの可能なすべての型をにできる必要があります。

OO言語では、関数は、(指定された制約内で)どのタイプを返すかを決定します。 Haskellでは、の呼び出し元であるが、返すタイプを決定します(指定された制約内で)。

このキーの違いを理解すると、残りの部分はかなり自明です。

再び、多くの人がこの部分を誤解しているようです。それはVFAQのように思われるので、私たちはおそらくチュートリアルやものでそれを言及する必要があります...

関連する問題