2011-11-30 4 views
5

これらの2つの関数型定義の違いは何ですか?以下の些細な関数定義の

printLength1::(Num a)=>String->a 
printLength1 s = length s 


printLength2::String->Int 
printLength2 s = length s 

なぜ彼らは同じではありませんか?どのような状況で私はもう一方を選ぶべきですか?

と私はprintLength1のため、このエラーが出る:

Couldn't match type `a' with `Int' 
     `a' is a rigid type variable bound by 
      the type signature for rpnc :: String -> a at test.hs:20:1 
    In the return type of a call of `length' 
    In the expression: length s 
    In an equation for `rpnc': rpnc s = length s 

私はこのエラーを理解しています。しかし、どうすればこの問題を解決できますか? 私はすでに剛体型変数についてここでいくつかの記事を読みましたが、それを修正する方法を理解できませんでした。 LearnYouAHaskell.com引用

答えて

9

最初の型シグネチャはより一般的です。結果は任意のNumであることを意味します - 戻り型で多型です。したがって、最初の関数の結果はIntまたはIntegerまたはその他のNumインスタンスとして使用できます。

lengthは、NumインスタンスではなくIntを返します。 (上記のコードのポイントフリーバージョン)fromIntegral . lengthの署名がNum c => [a] -> cあること

printLength1 :: Num a => String -> a 
printLength1 s = fromIntegral $ length s 

注:このfromIntegralを使用して固定することができます。これは、printLength1関数で指定した署名と一致します。

+0

ありがとうございます。私は言語に隠されたそのような癖はもうないと思います。 – osager

+3

@osagerこれは奇抜ではありませんが、これは型システムの非常に基本的に重要な部分です。多型型(少なくとも1つの多型型)は、それらがどのように使用されるかによって具体的な型に変換されます。タイプが多型であると主張するタイプシグネチャを書く場合、実際には多型である必要があります。 – Carl

+1

'Num'クラスは変わったものではありませんが、' Num'はむしろquirkではなく 'length'が' Int'であると合理的に主張することができます。 –

7

注:長さがintの代わりに、歴史的な理由のために民aを返すのIntので、この関数はnumLongChainsのタイプ::有します。より一般的なNum aを返すには、結果の長さにIntegralを使用することができます。

関連する問題