超どマイナー言語「ECLiPSe」を競プロで使ってみる

### 超軽く自己紹介
こんにちは、yaakiyuです。競技プログラミングをやっていたり、discordでbotを作っていたりします。AtCoder緑でまだまだよわよわプログラマーですがよろしくお願いします!

# ECLiPSeってなんじゃい？
僕がこの言語に出会ったのは[AtCoder ProblemsのLanguage Owner](https://kenkoooo.com/atcoder/#/lang)のランキングでのこと。自分でもランキングに乗れるような言語はないかなーと探していたときにECLiPSeという言語に出会った。2位の方が1ACだったので、なんとか1問ぐらい行けるだろ！と思って調べ始めた。

...見つからない！EclipseといえばJavaを開発するときの統合開発環境(IDE)が有名すぎて、まったくプログラミング言語のECLiPSeに出会わない。

これはAtCoder上の他の人のコードを見て学ぶしかないか...と見始めたところ、コンパイルメッセージのところに面白い文章が。

```
ECLiPSe Constraint Logic Programming System [kernel threads]
Kernel and basic libraries copyright Cisco Systems, Inc.
and subject to the Cisco-style Mozilla Public Licence 1.1
(see legal/cmpl.txt or http://eclipseclp.org/licence)
Source available at www.sourceforge.org/projects/eclipse-clp
GMP library copyright Free Software Foundation, see legal/lgpl.txt
For other libraries see their individual copyright notices
Version 7.1beta #13 (x86_64_linux), Sun Jan  1 18:01 2023
Main.ecl   compiled 744 bytes in 0.00 seconds

bye
```
「bye」って、かわいいな。というのは置いといて、僕が注目したのは途中のこの一文。
```
(see legal/cmpl.txt or http://eclipseclp.org/licence)
```
これ、後半の`http://eclipseclp.org/licence`って、公式ホームページの一部なんじゃない！？

と思ってlicenceの部分をURLから消したらありました。

> [ECLiPSe Home](https://eclipseclp.org/)

このサイトを見ながら基本文法とかを学びました。

# 1問解いてみる
まずは`Hello, world!`を出力するだけの問題を、いろいろ調べながら解いてみた。
https://atcoder.jp/contests/APG4b/submissions/46935632

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705690/fa3b7ccf-c0aa-1b00-22ba-69188853c539.png)
文法的には、
* main関数？の中に書く(引数っぽい部分がないのでこれが関数なのかはわからない...)
* write関数を使って出力(改行は自動的にはつかないので`\n`をつける必要あり)
* 最後(厳密には異なる)に`.`を書く

みたいな感じです。やってみて「マイナー言語にしては意外と機能多くて高級言語っぽいな〜」という感想でした。

# 文法解説
自分がわかる範囲で文法について解説します。間違っていたらコメントなどでご指摘ください。
### 入出力
入力は`read_string`、出力は`write`で可能です。read_stringの方は引数がいくつかついていますが、(自分でもよくわからないので)暗記したほうがいいでしょう。
```eclipse
main : 
    read_string(user_input, " \n", "", _, S),
    write(S).
```
ちなみに、2つ以上の動作を並列して書く場合、各行ごとに`,`で区切らないとコンパイルエラーが出ます。(最後の`.`は無くてもエラーは出ないが、あったほうがよさそう)
### コメント
`%`から始まる部分はコメントとしてみなされます。カンマも必要ありません。
```eclipse
main :-
    % ここはコメント。なにもしないぜ
    write("ここは文字列").
```
### 変数と数値計算
変数になにかを代入するときは`=`もしくは`is`を使います。
`=`では後に書かれたものがそのまま文字列として代入されますが、`is`を使うとその中身が実行されて代入されます。
数値計算を行う場合は`is`を使わなければ演算ができません。
```eclipse
main :-
    X = 5,
    write(X),  % 5
    Y = X * 2, 
    write(Y),  % X * 2
    A is X * 2,
    write(A).  % 10
```
# さいごに
おめでたいことにいろいろ調べながら4ACし、無事Language Ownerの2位に乗ることができました。...1位の方、65ACとかすごくないですか...!?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705690/1bec9609-4284-34c5-64a9-20159965198e.png)
# 追記：ナップサック問題を解く(!?)
いきなり高度なことができるようになりました。もちろん、公式サイトから辿っていったら例示コードがあったからなんですけど。
> [ECLiPSeWiki | Examples / Knapsack](https://eclipseclp.org/wiki/Examples/Knapsack)
```eclipse
%
% ECLiPSe SAMPLE CODE
%
% 0-1-Knapsack problem from
% http://rosettacode.org/wiki/Knapsack_problem
% Pack 0 or 1 item of each type, obeying knapsack weight constraint.
%
% Using ic (as a finite-domain solver) and ic_sets (set-solver)
%

:- lib(ic).
:- lib(ic_sets).
:- lib(branch_and_bound).

model(Weights, Values, Capacity, Knapsack, Weight, Value) :-
	dim(Weights, [N]),
	dim(Values,  [N]),
	intset(Knapsack, 1, N),		% Knapsack is a subset of integers 1..N
	Weight #=< Capacity,
	weight(Knapsack, Weights, Weight),
	weight(Knapsack, Values, Value).

solve(Weights, Values, Capacity, Knapsack, Weight, Value) :-
	model(Weights, Values, Capacity, Knapsack, Weight, Value),
	Cost #= -Value,		% need Cost for minimizing!
	minimize(insetdomain(Knapsack,_,heavy_first(Values),in_notin), Cost).

main :-
    	data(Names, Weights, Values, Capacity),
	solve(Weights, Values, Capacity, Knapsack, Weight, Value),
	( foreach(I,Knapsack), param(Names) do
	    arg(I, Names, Name),
	    writeln(Name)
	),
	writeln(weight=Weight;value=Value).


% data(Names, Weights, Values, Capacity)
data(
    [](map,compass,water,sandwich,glucose,tin,banana,apple,cheese,beer,
       'suntan cream',camera,'t-shirt',trousers,umbrella,'waterproof trousers',
       'waterproof overclothes','note-case',sunglasses,towel,socks,book),
    [](  9,13,153, 50,15,68,27,39,23,52,11,32,24,48,73,42,43,22, 7,18, 4,30),
    [](150,35,200,160,60,45,60,40,30,10,70,30,15,10,40,70,75,80,20,12,50,10),
    400
).
```
このコードを(フィーリングで)読む感じ、いくつか知らなかった文法構造とか関数がありそうです。
あと最近いろいろテストしていて気が付いたことも含めて説明します。
- 空白やハイフンを含まない文字列は引用符が不要
- すべての変数がデフォルトでconstになっていて、再代入ができない
- writeln関数がある
```eclipse
writeln("aaa"). % 「aaa\n」を出力
```
- いきなり出てきた`Cost #= -Value`、`#=`は何もわからないけどとりあえずCostがもとからなにか用意されたものっぽそうなのを確認
```eclipse
main:-
    writeln(Cost). % 「_15297」が出力された
```
- ライブラリのインポートをしている(ということは標準ライブラリがある)
```eclipse
:- lib(ライブラリ名).
```
でインポート可能。

ほかになにかECLiPSeについて知っている方がいたらどうかコメント欄に情報お願いします。