0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiita Engineer Festa 2024(キータ・エンジニア・フェスタ 2024) - Qiita
において、約1ヶ月で38記事という大量の記事の投稿を要求されることがわかった。
そこで、あまりコストをかけずに記事数を稼ぐ方法を考えた結果、「Welcome to AtCoder を様々な言語で解く」ことを思いついた。
単に解くだけでなく、使用する言語仕様の解説を入れれば、記事として一応成立するだろう。

Welcome to AtCoder

PracticeA - Welcome to AtCoder

Welcome to AtCoder では、以下の形式で整数 $a$, $b$, $c$ および文字列 $s$ が入力として与えられる。

a
b c
s

この入力をもとに、与えられた整数の和 $sum = a + b + c$ および文字列 $s$ を、以下の形式で出力することが求められる。

sum s

今回用いた OCaml の機能

定数と関数の定義

Expressions and Definitions
Functions
Recursive Functions

let 名前 = ;;

のように書くことで、定数を定義できる。
それぞれの定義の後に ;; をつける。

let が連続する場合など、;; をつけなくてもいい場合もあるようである。
しかし、後述の出力を行う場合など、;; をつけないとエラーになる場合もあるようである。
;; はつけておくのが安全だろう。

let 名前 =  in 

のように書くことで、「式」の中でしか使わない定数を定義できる。

この let … in … 全体も式である。

let 関数名 引数名1 引数名2  = ;;

のように書くことで、(再帰しない) 関数を定義できる。

let rec 関数名 引数名1 引数名2  = ;;

のように書くことで、再帰関数を定義できる。

すなわち、再帰関数を定義する場合は、通常の let に続いて空白と rec を書く。

パターンマッチ (リストの要素の取り出し)

Lists

match リスト with
| [] -> リストが空の場合の式
| x :: xs -> リストが空でない場合の式

と書くと、リストが空のときと空でないときで処理を分け、さらにリストの最初の要素を取り出すことができる。
「リストが空でない場合の式」において、x が「リスト」の最初の要素、xs が「リスト」から最初の要素を取り除いたリストである。

整数の処理

OCaml library : Int

a + b

により、ab の和を求めることができる。

a - b

により、a から b を引いた差を求めることができる。

a * b

により、ab の積を求めることができる。

Int.to_string 

により、「値」を十進数で表した文字列を得ることができる。

文字列の処理

OCaml library : String

a ^ b

により、文字列 ab を連結した文字列を得ることができる。

String.make 個数 文字

により、「文字」を「個数」回繰り返した文字列を得ることができる。

String.get 文字列 位置

により、「文字列」の「位置」番目 (0-origin) の文字を得ることができる。

String.get_uint8 文字列 位置

により、「文字列」の「位置」番目のバイトを整数 (int) で得ることができる。

String.split_on_char 文字 文字列

により、「文字列」を「文字」で区切った文字列のリストを得ることができる。

String.fold_left 関数 初期値 文字列

により、「初期値」から「文字列」のそれぞれの文字について左から順に「関数」で処理した結果を得ることができる。
「関数」は、「今の値」と「処理する文字」を引数にとる。
すなわち、以下のような処理を行う。

function fold_left(func, initial_value, str) {
    let value = initial_value;
    for (let i = 0; i < str.length; i++) {
        value = func(value, str.charAt(i));
    }
    return value;
}

入出力

Side-Effects and the unit Type

read_line ()

により、標準入力から1行読み込み、結果を文字列として得ることができる。
得られる文字列には、末尾に改行文字は含まれない。

これは、read_line 関数に引数 () (unit) を渡している。

print_endline 文字列;;

により、標準出力に「文字列」 (String) を出力し、さらに改行を出力できる。

提出コード

let str_to_int_step value ch =
  let ch_str = String.make 1 ch
  in value * 10 + (String.get_uint8 ch_str 0) - 48
;;

let str_to_int s =
  String.fold_left str_to_int_step 0 s
;;

let rec sum_list l s =
  match l with
  | [] -> s
  | x :: xs -> sum_list xs (s + (str_to_int x))
;;

let line1 = read_line ();;
let line2 = read_line ();;
let line3 = read_line ();;

let bc_str = String.split_on_char (String.get " " 0) line2;;

let a = str_to_int line1;;
let sum = sum_list bc_str a;;
let result_str = (Int.to_string sum) ^ " " ^ line3;;

print_endline result_str;;

提出 #54993981 - AtCoder Beginners Selection

提出コードの解説

let str_to_int_step value ch =
  let ch_str = String.make 1 ch
  in value * 10 + (String.get_uint8 ch_str 0) - 48
;;

文字列の数値への変換を一桁進める。
文字を String.make で文字列に変換し、さらに String.get_uint8 で文字コードに変換する。
この桁の数値は、変換結果から 0 の文字コードを引いた値である。
1個上の桁までの変換結果に (十進数なので) 10 を掛け、さらにこの桁の数値を足すことで変換を進める。

let str_to_int s =
  String.fold_left str_to_int_step 0 s
;;

String.fold_left を用い、各桁の変換を行うことで、文字列をそれが表す数値に変換する。

let rec sum_list l s =
  match l with
  | [] -> s
  | x :: xs -> sum_list xs (s + (str_to_int x))
;;

数値を表す文字列のリストについて、それらを数値に変換しながら、和を求める。

let line1 = read_line ();;
let line2 = read_line ();;
let line3 = read_line ();;

入力の各行を読み込む。

let bc_str = String.split_on_char (String.get " " 0) line2;;

2行目を空白で分割する。
String.get を用いて文字を用意している。

let a = str_to_int line1;;
let sum = sum_list bc_str a;;

1行目の文字列を数値に変換し、それに2行目の文字列の各部分が表す数値を加算して和を求める。

let result_str = (Int.to_string sum) ^ " " ^ line3;;

print_endline result_str;;

求めた和・空白・3行目を連結し、出力する。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?