社員ブログ
HOME  社員ブログ

アーカイブ

‘雑記’ カテゴリ

Scalaファイルにパッケージ宣言が含まれているとScalaインタープリタでエラー

2015年10月14日 18時02分27秒

こんにちは、ピーターです。

突然ですが、パッケージ宣言が含まれているScalaファイルをScalaインタープリタで実行したいとします。

package chapter1

object Mine {

  def fib(n: Int): Int = {

    def loop(a: Int, b: Int, i:Int): Int = {
      if (n == 0) {
        0
      } else if (n == 1) {
        1
      } else if (i < n) {
        loop(b, a + b, i + 1)
      } else {
        a + b
      }
    }

    loop(0, 1, 2)
  }

  def main(args: Array[String]): Unit = {
    println(fib(10)) // 55
  }

}


scalaコマンドで実行した場合:

scala chapter1/Mine.scala

chapter1/Mine.scala:1: error: illegal start of definition
package chapter1
^
one error found


REPL(対話モード)の:loadコマンドで実行した場合:

scala> :load chapter1/Mine.scala

<console>:1: error: illegal start of definition
package chapter1
^
defined object Mine


どちらで実行してもパッケージ宣言があるためにエラーになってしまいます。

パッケージ宣言をコメントアウトすればエラーにならずに実行できますが、今回はREPL(対話モード)の:pasteコマンドを使った方法をご紹介します。

  1. scalaコマンドでREPLを起動します。
  2. REPLで:pasteコマンドを実行して貼り付けモードにします。
  3. パッケージ宣言を除いたコードを貼り付けます。
        コードの最後に空行がない場合は貼り付け後に空行を追加してください。
        でないと貼り付けモードを終了できないようです。
  4. ctrl + Dで貼り付けモードを終了します。

これでコードが読み込まれました。
読み込まれただけではmainメソッドは呼ばれませんので、mainメソッドは自分で呼びます。

scala> Mine.main(null)
55

正常に実行できました。


社員:ピーター, 雑記

関数型プログラミングの練習問題 (Scala)

2015年09月24日 22時28分50秒

こんにちは、ピーターです。

Scala関数型デザイン&プログラミング」という関数型プログラミングの入門書を読み始めまして、その中に練習問題がたくさん出てくるのですが、その最初の練習問題について書こうと思います。

その問題はこちらです。

n番目のフィボナッチ数を取得する再帰関数を記述せよ。
最初の2つのフィボナッチ数は0と1である。
n番目の数字は常に前の2つの数字の合計となる。
この数列は0, 1, 1, 2, 3, 5のように始まる。
再帰関数の定義では、ローカルな末尾再帰関数を使用すること。

「ローカルな」というのは、関数の中に関数を定義するということです。
末尾再帰というのは、呼び出し元が再帰呼び出しした結果の値を返す以外にはもう何もしないということです。例えば、再帰呼び出しした結果の値に+1して返すと末尾再帰ではなくなります。

そして僕が考えたコードはこちらです。

def fib(n: Int): Int = {

  def loop(a: Int, b: Int, i:Int): Int = {
    if (n == 0) {
      0
    } else if (n == 1) {
      1
    } else if (i < n) {
      loop(b, a + b, i + 1)
    } else {
      a + b
    }
  }

  loop(0, 1, 2)
}

nになるまで最初から2つの数字を足していく考え方です。
そして解答はこちらです。

def fib(n: Int): Int = {

  def loop(n: Int, prev: Int, cur: Int): Int = {
    if (n == 0) {
      prev
    } else {
      loop(n - 1, cur, prev + cur)
    }
  }

  loop(n, 0, 1)
}

こちらはnが0になるまでデクリメントしながら2つの数字を足していき、0になったらそれまでの値を返しています。

僕の方はforループ的な考え方なのですが、解答の方はより再帰的な考え方になっているのかなと思います。より再帰的に考えられることで、こうしてシンプルなコードになるんだなと思いました。


社員:ピーター, 雑記

[CSS]背景画像を中央から相対指定する方法

2015年08月25日 12時12分00秒

こんにちは、ピーターです。
最近はCSSをよく書いています。


例えば、1280pxの幅のページに、500pxの画像を横に3つ並べたいとします。
その時、「text-align: center;」したように中央に寄せる必要があるとします。
こんなイメージです。


スクリーンショット 2015-08-25 11.20.35


これを実現するのは簡単です。


HTML:

<div id="images"><!--
    --><img src="left.png" /><!--
    --><img src="center.png" /><!--
    --><img src="right.png" /><!--
--></div>

CSS:

#images {
    width: 1500px;
    position: relative;
    left: 50%;
    margin-left: -750px;
}


これだけです。


まず、画像を3つ並べます。
img間の<!– –>は、img間の隙間をなくすためのものです。
これだけでは中央に寄りませんので、1500pxのdivの左端を中央に合わせ、幅の半分をネガティブマージンとすることで中央に寄せています。


しかしこの場合、1500pxに対してページ幅が1280pxなので、横スクロールバーが出てしまいます。横スクロールバーが出てもいい場合もあると思いますが、出したくない場合もあると思います。横スクロールバーを出さないようにするにはどうすればいいでしょうか。


CSSのbackgroundプロパティを使ってみたらどうでしょうか。


HTML:

<div id="images"></div>

CSS:

#images {
    width: 1500px;
    height: 500px;
    position: relative;
    left: 50%;
    margin-left: -750px;
    background:
        url(left.png)   no-repeat left   top,
        url(center.png) no-repeat center top,
        url(right.png)  no-repeat right  top;
}


これも横スクロールバーが出てしまいます。


横スクロールバーが出る原因は、ページ幅を超えるwidth指定です。
なのでまずは「width: 1500px;」を外します。
中央に寄せたdivでなくても、背景画像を中央に表示するのは簡単です。


HTML:

<div id="images"></div>

CSS:

#images {
    height: 500px;
    background: url(center.png) no-repeat center top;
}


これで1枚の画像を中央に表示することができます。
では、左右の画像はどうしたらいいでしょうか。


background-positionプロパティは、位置を相対指定できます。

 

background: url(left.png) no-repeat left 5px top 10px;


これで、左から5px、上から10pxとなります。
これを使って、中央からの位置を指定すれば良さそうです。

 

background: url(left.png) no-repeat center -500px top;


残念ながら、left, right, top, bottomからの位置は指定できるのですが、centerからの位置は指定できません。
そこでcalc関数を使ってみます。


HTML:

<div id="images"></div>

CSS:

#images {
    height: 500px;
    background:
        url(left.png)   no-repeat calc(50% - 500px) top,
        url(center.png) no-repeat center top,
        url(right.png)  no-repeat calc(50% + 500px) top;
}


たしかにこれはうまくいきます。横スクロールバーも出ません。


しかしIEだけは、background-positionプロパティにcalc関数を使うとうまくいかないという問題があります。


別の方法を考えてみます。
width: 50%; のインラインブロックを2つ横に並べることで、左のインラインブロックの右端と、右のインラインブロックの左端が中央の位置になります。このことを利用して、インラインブロックの右端または左端からの位置を指定した背景画像とすれば良さそうです。


HTML:

<div id="images"><!--
    --><div class="left"></div><!--
    --><div class="right"></div><!--
--></div>

CSS:

#images {
    height: 500px;
    background: url(center.png) no-repeat center top;
}
#images > div {
    display: inline-block;
    width: 50%;
    height: 100%;
}
#images .left {
    background: url(left.png) no-repeat right 250px top;
}
#images .right {
    background: url(right.png) no-repeat left 250px top;
}


これでうまくいきました。IEでも問題ありません。
真ん中の画像は外側のdivの中央に表示しています。
左の画像は右から250px、右の画像は左から250pxの位置とすることで、中央からの位置指定を行っています。


最後のソースの全ソースと画像はこちらです。

left.png
center.png
right.png

 

<!DOCTYPE html>
<html>
<head lang="ja">
    <meta charset="UTF-8">
    <title>[CSS]背景画像を中央から相対指定する方法</title>
    <style>
        body { margin: 0; }

        #images {
            height: 500px;
            background: url(center.png) no-repeat center top;
        }
        #images > div {
            display: inline-block;
            width: 50%;
            height: 100%;
        }
        #images .left {
            background: url(left.png) no-repeat right 250px top;
        }
        #images .right {
            background: url(right.png) no-repeat left 250px top;
        }
    </style>
</head>
<body>
    <div id="images"><!--
        --><div class="left"></div><!--
        --><div class="right"></div><!--
    --></div>
</body>
</html>

 


CSS, 社員:ピーター