function :: (Floating a, RealFrac a, Integral b) => a -> b
function x = floor (sqrt x)
さて、この関数を見ると、型クラスと型クラスのa
両方にRealFrac
なりFloating
、次にb
であると指定しましたIntegral
。これはの署名であるfloor
とsqrt
:
floor :: (Integral b, RealFrac a) => a -> b
sqrt :: Floating a => a -> a
ように見ることができるsqrt
唯一のとりFloating
秒とfloor
だけ取りますRealFrac
。私はセットa
にRealFrac
してFloating
。それから私はそれb
が私たちにを与えるIntegral
のでそうなるだろうと指定しましfloor
たIntegral
。
だから私の質問は
newfunction :: (Integral a, RealFrac a, Integral b) => a -> b
newfunction a = floor (sqrt (fromIntegral a))
なぜこれが機能しないのですか?
実際の正しいタイプの署名は
newfunction :: (Integral a, Integral b) => a -> b
なぜこれが機能しないのですか?
...しかし、それはします:
Prelude> :{
Prelude| let newfunction :: (Integral a, RealFrac a, Integral b) => a -> b
Prelude| newfunction a = floor (sqrt (fromIntegral a))
Prelude| :}
Prelude> :t newfunction
newfunction :: (Integral a, Integral b, RealFrac a) => a -> b
GHCに型シグネチャを自動的に推測させると、よりシンプルで優れたシグネチャが作成されます。
Prelude> let newfunction a = floor (sqrt (fromIntegral a))
Prelude> :t newfunction
newfunction :: (Integral b, Integral a) => a -> b
しかし、それは手動で指定されたものが間違っていることを意味するものではありません。状況に応じて、それが求めているものである場合とそうでない場合があります。
何かがより一般的であるとはどういう意味かというと、それは仮定を少なくし、入力に課す要件/制約を少なくするときです。必要なものが少なくなることで、さまざまな入力を処理できます。これは「より一般的」と呼ばれます。
また、この場合のあまり一般的でないバージョンは、実際には何も呼び出せないため無効ですが、Haskellではそのような関数を定義できます。失敗は呼び出しサイトで発生します。
Prelude> :i RealFrac
class (Real a, Fractional a) => RealFrac a where
...
-- Defined in ‘GHC.Real’
instance RealFrac Float -- Defined in ‘GHC.Float’
instance RealFrac Double -- Defined in ‘GHC.Float’
Prelude> :i Integral
class (Real a, Enum a) => Integral a where
...
-- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
-シングルタイプは両方に属しているか見ないRealFrac
とIntegral
同時に?手動で定義した場合は機能しますinstance RealFrac Integer where ...
が、それはおそらく意味がなく、一部の型クラスの法則に違反する可能性があり、したがって一貫性のない/バグのあるコードにつながる可能性があります。
したがって、一般的なガイドラインとして、 GHCで推測される型の署名から始めてから、制約を追加するか、署名をより単形/多形にしないでください。
さらに、これらの関数をポイントフリーで定義することもできます。これにより、読みやすくなると思います。現在の括弧付きバージョンをポイントフリーバージョン(暗黙とも呼ばれる)に変換する方法を以下に示します。
function x = floor (sqrt x)
function x = floor . sqrt $ x
function = floor . sqrt
newfunction a = floor (sqrt (fromIntegral a))
newfunction a = floor . sqrt . fromIntegral $ a
newfunction = floor . sqrt . fromIntegral
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加