Juliaが良さそうなので年末年始に少しでも知識を付けようと勉強中(1日目)。とりあえず書き方に慣れないと話にならないので、AtCoder過去問で練習していたら、初手で死亡したのでメモ。
Julia Version
$ julia --version
julia version 1.4.1
お題
前の値と次の値を比較して up
とか down
とか判定しろという問題。こんなの1分で解かないといけない。
え、その変数見えへんの?
とりあえず標準入力を1行1行取り出し、数値にして前の値と比較するという愚直なプログラム。**次の行を見る前に現在の値を前の値として記憶しておく。**問題の本質では無いので break
条件についてはとりあえず考慮しない。
using Printf
aprev = 0 # aprevを宣言
while true
snext = readline()
anext = parse(Int, snext)
df = anext - aprev
if df > 0
@printf("up %d\n", df)
elseif df < 0
@printf("down %d\n", abs(df))
else
println("stay")
end
aprev = anext # aprevに現在の値を記憶
end
別に変哲もないプログラムでしょう。でもこれコンパイルエラーになります。
$ julia 2019b.jl
1
ERROR: LoadError: UndefVarError: aprev not defined
Stacktrace:
[1] top-level scope at /home/morita/workspace/jlexp/2019b.jl:29
[2] include(::Module, ::String) at ./Base.jl:377
[3] exec_options(::Base.JLOptions) at ./client.jl:288
[4] _start() at ./client.jl:484
in expression starting at /home/morita/workspace/jlexp/2019b.jl:26
は?aprev not defined
て何でなの。
localスコープからglobal変数は見えません
多分スコープの問題だろうと調べものをしたらこのような記事が。https://marui.hatenablog.com/entry/2019/08/09/115410
どうも問題はトップレベルで書かれた行はglobal変数として扱われ、それはlocal変数から見えない、という事が落ちな模様。気持ち悪いのは、while
やfor
などのループは新しいlocalスコープを作るということ!公式サイトに具体例もちゃんと書かれていました。 https://docs.julialang.org/en/v1.1/manual/variables-and-scoping/#Local-Scope-1
公式の説明↓
https://docs.julialang.org/en/v1.4/manual/variables-and-scoping/#man-scope-table-1
There are two main types of scopes in Julia, global scope and local scope. The latter can be nested. The constructs introducing scope blocks are ... (while, forなど)
つまり、while
やfor
などは、localスコープのコンストラクタという事。また、localスコープはネストされるので、親forループ内で宣言されたlocal変数は、子forループ内でも参照できます。
解決方法
1つの方法は、forループの外の変数を global
宣言してあげる事です。
aprev = 0
while true
global aprev # global宣言
snext = readline()
anext = parse(Int, snext)
df = anext - aprev
...(snip)...
end
でも global
変数って何か気持ち悪いですよね。他の解決方法としては、ちゃんと関数として宣言してあげる事です。
using Printf
function f()
aprev = 0
while true
snext = readline()
anext = parse(Int, snext)
df = anext - aprev
if df > 0
@printf("up %d\n", df)
elseif df < 0
@printf("down %d\n", abs(df))
else
println("stay")
end
aprev = anext
end
end
f()
これで動きます。
まとめ
関数くらいはちゃんと書くか。