ie-developers / ie-questions

public questions for ie students.
10 stars 0 forks source link

ghciでの定数と関数の型の変化 #10

Open maeken2010 opened 9 years ago

maeken2010 commented 9 years ago

除算の小数部分を求めたくて以下の関数syoussと定数n,mを用意したのですが,

syouss n m = (n/m) - (fromIntegral (n`div`m))
n = 10
m = 3

ghciで:loadで読み込んで実行しようとするとエラーに

ghci> syouss n m
<interactive>:3:1:
    No instance for (Fractional Integer) arising from a use of ‘syouss’
    In the expression: syouss n m
    In an equation for ‘it’: it = syouss n m

nとmの型を調べるとなぜかIntegerでした. ghciでlet a = 10のようにすると型はa :: Num a => aとなりましたがsyoussはまだ実行できませんでした.

ghci> let a = 10
ghci> let b = 3
ghci> :t a
a :: Num a => a
ghci> syouss a b

<interactive>:8:1:
    No instance for (Show a0) arising from a use of ‘print’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Show Double -- Defined in ‘GHC.Float’
      instance Show Float -- Defined in ‘GHC.Float’
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 44 others
    In a stmt of an interactive GHCi command: print it

試しにghciで(a/b) - (fromIntegral (adivb))を直接実行すると計算できました.

ghci> (a/b) - (fromIntegral (a`div`b))
0.3333333333333335

型を見てみましたがなぜか異なっていました

ghci> :t (a/b) - (fromIntegral (a`div`b))
(a/b) - (fromIntegral (a`div`b)) :: Fractional a => a
ghci> :t syouss
syouss :: (Integral a, Fractional a) => a -> a -> a

長くなってしまいまいましたが,以上より2つの疑問点があります.

  1. 定数の型がファイルからの:loadとghciでのletで何故型が違うのか
  2. 数式(a/b) - (fromIntegral (adivb))を関数定義した時と直接実行した時に何故型が変わるのか
maeken2010 commented 9 years ago

書きながら思ったのですが除算の小数部分自体はRatio用いる方法がありますね.このままでは整数値同士しかできませんが…

import Data.Ratio
syous n m = fromRational $ (n`mod`m) % m 
atton commented 9 years ago

まず2 から答えます。

  1. 数式(a/b) - (fromIntegral (adivb))を関数定義した時と直接実行した時に何故型が変わるのか

についてですけれど、 ghci で定義している文だと関数じゃなくて定数だからです。

syouss は関数なので、

ではなくて

です。

そうすると

Prelude> :t \a b -> (a/b) - (fromIntegral (a`div`b))
\a b -> (a/b) - (fromIntegral (a`div`b))
  :: (Integral a, Fractional a) => a -> a -> a

*Main> :t syouss 
syouss :: (Integral a, Fractional a) => a -> a -> a

と同じです。

そして、 Int の値が実行できない問題はこっちでも発生します。

*Main> (\a b -> (a/b) - (fromIntegral (a`div`b))) (10 :: Int) (3 :: Int)

<interactive>:17:12:
    No instance for (Fractional Int) arising from a use of ‘/’
    In the first argument of ‘(-)’, namely ‘(a / b)’
    In the expression: (a / b) - (fromIntegral (a `div` b))
    In the expression: \ a b -> (a / b) - (fromIntegral (a `div` b))

これはどうしてかと言えば Int だと Fractional に明示的に変換しないといけないからです。

Num, Fractional, Integral の関係は https://www.haskell.org/onlinereport/basic.html とかになってます。

Integral である Integer にすると、 Fractional の型クラスを持ってないからエラーになるわけです。

atton commented 9 years ago

ん? ごめんちょっと問題を勘違いしてたかも。 上の全然関係無いこと言ってる説が。ちょっと待って