質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.02%

  • Haskell

    48questions

    Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

  • GHC

    4questions

    Glasgow Haskell Compiler(GHC) は Haskell コンパイラです 異なる複数のアーキテクチャのネイティブコードや、C言語へコンパイルする事ができます。

`^' の Warning

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 884

zeroyonichikyu

score 29

Haskell 学習中に理解できない Warning に突き当たったので、どなたかご教授いただければと思います。
最小構成とWarning の内容を以下に記載します。

{-# OPTIONS -Wall -Werror #-}

square' :: Double -> Double
square' x = x ^ 2

test.hs:5:15: Warning:
    Defaulting the following constraint(s) to type `Integer'
      (Integral b0) arising from a use of `^' at test.hs:5:15
      (Num b0) arising from the literal `2' at test.hs:5:17
    In the expression: x ^ 2
    In an equation for square': square' x = x ^ 2

環境は以下の通りです。

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3
よろしくお願いします。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

check解決した方法

+3

@takotakot さんの回答をヒントに warning の理由について調べ、

*Main> :t (^)
(^) :: (Integral b, Num a) => a -> b -> a
*Main> :t (**)
(**) :: Floating a => a -> a -> a
*Main> :t (^^)
(^^) :: (Fractional a, Integral b) => a -> b -> a
*Main> :t 2
2 :: Num a => a

と、ここでようやくエラーメッセージの意味が理解出来ました。
(エラーではないのは定義上は不一致だが、計算上は問題ないと推論されたからでしょうか)

ご提案の通り ** を使用するか、

square' :: Double -> Double
square' x = x ^ (2 :: Int)

とすれば warning がでないことを確認しました。

累積の演算子が3種類ある理由や使い分けがまだイメージできませんが、今後の課題にしたいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+3

 処理系がデフォルトの型を使ったという警告です

 どうして型が決定できないか

読みやすさのために、質問者のコードを再掲します。

{-# OPTIONS -Wall -Werror #-}

square' :: Double -> Double
square' x = x ^ 2

このエラーは数値リテラル2の型が決定できないために、生じています。
Haskellでは数値リテラルの型は多相性を持ちます。
対話環境で、つぎのように試してみてください。

> 2 :: Integer
2
> :type it
it :: Integer
> 2 :: Double
2.0
> :type it
it :: Double
> :type 2
2 :: Num t => t

数値リテラル2は多相的であり、実際に計算が行われるときには、Numクラスに含まれる、どれかの型に決定されます。

さて、演算子(^)の型を見てみましょう。

(^) :: (Num a, Integral b) => a -> b -> a

第1引数はNumクラスに含まれる型の値、第2引数はIntegralクラスに含まれる型の値、返り値は第1引数と同じ型の値、となります。
ここで、問題の式を見てみましょう。

x ^ 2

リテラル2はNumクラスである型の値となります。また、演算子(^)を適用していることから、よりきびしく、Integralクラスの型の値であることを要求されます。しかし、それだけです。これだけでは数値2の型が定まりません。

 型の決まらない「整数値」のデフォルトはInteger

ここで、Haskellには、型の決まらない「整数値」をデフォルトでIntegerとする、というルールがあります。そのルールで数値2の型はIntegerとなります。
しかし、この「デフォルトの型」はコードを書いた人の意図とは異なるかもしれません。そこで警告が出ます。

解決の方法の、いくつかを挙げます。
まず、質問者が -Wall -Werror としているのは大変良い習慣かと思います。
そこで、それを生かす方向で、いくつかの解決策を挙げておきます。

 デフォルトの型を使うことへの警告をつぶす

コードを書く人が、Haskellがデフォルトとして選ぶ型を信頼しているなら、つぎのようにします。

{-# OPTIONS -Wall -fno-warn-type-defaults -Werror #-}

こうすると、Haskellがデフォルトの型を選択したときに、警告しなくなります。

 型注釈をつける

より、おすすめの方法は、型注釈をつけることです。

square' x = x ^ (2 :: Integer)

このようにすれば、明示的に数値2の型をIntegerと特定することができます。
Int型の値のほうが、すこしだけ、空間効率が良い気がするので、つぎのようにするのも、いいかもしれません。

square' x = x ^ (2 :: Int)

 演算子(**), (^), (^^)について

それぞれの型を再掲します。

(**) :: Floating a => a -> a -> a
(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a

実は、型だけからでも、あるていど、これらのちがいは予想できます。
演算子(**)では、冪乗する数である第2引数はFloatingクラスの型の値です。
つまり、浮動小数点っぽい値だということです。
整数でなくてもいい、つまり、つぎのようなことができます。

> 3 ** 0.5
1.7320508075688772

それに対して、演算子(^)では、第2引数は整数値です。
つまり、x ^ yは、「xをy回、かけあわせたもの」です。
このとき、xはNumクラスのインスタンスである型の値なら、何でもいいです。
Numクラスのクラス関数に「かけ算」があるためです。

最後の(^^)については、第1引数がFractionalクラスの型、つまり、分数(小数)となっています。整数では、負の数での冪乗ができないためです。

> 2 ^ (- 1)
Exception: Negative exponent
> 2 ^^ (- 1)
0.5

 どうして、(**)で解決したか

演算子(**)の型は、つぎのようになっています。

(**) :: Floating a => a -> a -> a

質問者が新しく定義した関数は、つぎのようになります。

square' :: Double -> Double
square' x = x ** 2

演算子(**)は、第1引数、第2引数、返り値のすべてが同じ型であることを、要求しています。
そしてsquare'では引数と返り値とがDouble型の値であることを、要求します。
これらから、数値2の型がDouble型に決定されます。

ただ、この解決は、あまり好ましくないと感じます。
「ある数を、1.5乗でもなく2.5乗でもなく2乗したい」という意図であれば、
上記の解決策がぴったりですが、
「ある数を、2回かけあわせたい」という意図であれば、演算子(^)が、ぴったりかと思います。
そして、第2引数の数値リテラルには、好みの整数型を指定してあげるのが良いと思われます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/30 12:03

    丁寧かつ詳細な解説ありがとうございます. 質問したときは数値リテラルの型についてよくわかっておらず, 混乱していました.

    teratailのUIに慣れておらず, 今方法を調べていますが, 分かり次第解決した方法をこちらの回答に付け替えさせていただきます.

    キャンセル

  • 2017/05/30 17:00

    こちらこそ、良い質問を、ありがとうございました。

    キャンセル

-1

英語で何と書いてあるか、分かりますか?キーワードは Integer。エラーメッセージはきちんと読みましょう。「Haskell 累乗」で検索するだけで見つかりますよ?
Haskell基礎文法最速マスター を読めば、どの演算子を用いればよいか分かります。** を用いるべきですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/27 13:19

    ありがとうございます。

    キャンセル

  • 2015/05/27 13:29

    Wallオプションを外すとコンパイルが通り、結果も問題なかったので、演算子そのものが間違いとは思いつきませんでした。

    Integer と ^ と ** については調べてみます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Haskell

    48questions

    Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

  • GHC

    4questions

    Glasgow Haskell Compiler(GHC) は Haskell コンパイラです 異なる複数のアーキテクチャのネイティブコードや、C言語へコンパイルする事ができます。