Last active
August 29, 2015 14:13
-
-
Save lnznt/61c9c4bfb5eeca72bf72 to your computer and use it in GitHub Desktop.
Ruby: Prologで翻訳「時の蝿はひとつの矢を好む」 ref: http://qiita.com/lnznt/items/72abba6b045ef4ffafae
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
s(s(NP,VP)) --> np(NP), vp(VP). % 文 -> 名詞句 動詞句 | |
s(s(NP)) --> np(NP). % 文 -> 名詞句 | |
s(s(VP)) --> vp(VP). % 文 -> 動詞句 | |
np(np(N)) --> n(N). % 名詞句 -> 名詞 | |
np(np(A,N)) --> adj(A), n(N). % 名詞句 -> 形容詞 名詞 | |
np(np(D,N)) --> det(D), n(N). % 名詞句 -> 冠詞 名詞 | |
vp(vp(V)) --> v(V). % 動詞句 -> 動詞 | |
vp(vp(V,NP)) --> v(V), np(NP). % 動詞句 -> 動詞 名詞句 | |
vp(vp(V,PP)) --> v(V), pp(PP). % 動詞句 -> 動詞 前置詞句 | |
vp(vp(V,NP,PP)) --> v(V), np(NP), pp(PP). % 動詞句 -> 動詞 名詞句 前置詞句 | |
pp(pp(P,NP)) --> prep(P), np(NP). % 前置詞句 -> 前置詞 名詞句 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
n(n(time)) --> [time]. | |
n(n(flies)) --> [flies]. | |
n(n(arrow)) --> [arrow]. | |
v(v(time)) --> [time]. | |
v(v(flies)) --> [flies]. | |
v(v(like)) --> [like]. | |
adj(adj(time)) --> [time]. | |
prep(prep(like)) --> [like]. | |
det(det(an)) --> [an]. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
js(s(NP,VP)) --> jnp(NP),['は'],jvp(VP). % 文 -> 名詞句 'は' 動詞句 | |
js(s(NP)) --> jnp(NP). % 文 -> 名詞句 | |
js(s(VP)) --> jvp(VP). % 文 -> 動詞句 | |
jnp(np(N)) --> jn(N). % 名詞句 -> 名詞 | |
jnp(np(A,N)) --> jadj(A), jn(N). % 名詞句 -> 形容詞 名詞 | |
jnp(np(D,N)) --> jdet(D), jn(N). % 名詞句 -> 冠詞 名詞 | |
jvp(vp(V)) --> jv(V). % 動詞句 -> 動詞 | |
jvp(vp(V,NP)) --> jnp(NP),['を'],jv(V). % 動詞句 -> 名詞句 'を' 動詞 | |
jvp(vp(V,PP)) --> jpp(PP),jv(V). % 動詞句 -> 前置詞句 動詞 | |
jvp(vp(V,NP,PP)) --> jnp(NP),['を'],jpp(PP),jv(V). % 動詞句 -> 名詞句 'を' 前置詞句 動詞 | |
jpp(pp(P,NP)) --> jnp(NP),jprep(P). % 前置詞句 -> 名詞句 前置詞句 | |
translate(Japanese, English, Semantics) :- | |
s(Semantics, English, []), | |
js(Semantics, Japanese, []). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jn(n(time)) --> ['時間']. | |
jn(n(flies)) --> ['蝿']. | |
jn(n(arrow)) --> ['矢']. | |
jv(v(time)) --> ['拍子'],['を'],['合わせる']. | |
jv(v(flies)) --> ['飛ぶ']. | |
jv(v(like)) --> ['好む']. | |
jadj(adj(time)) --> ['時'],['の']. | |
jprep(prep(like)) --> ['の'],['よう'],['に']. | |
jdet(det(an)) --> ['ひとつ'],['の']. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rake daemon[drb_uri,port,host,encoding] # drb デーモンとして起動 | |
rake en[sentence] # 翻訳: 日本語 -> 英語 | |
rake jp[sentence] # 翻訳: 英語 -> 日本語 | |
rake load[files] # ファイルのロード | |
rake server[port,server_program] # Prolog サーバの起動 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: | |
: server は 'server.pro' があるディレクトリで、 | |
: load は 'dcg-*.pro' があるディレクトリで実行します。 | |
: | |
$ rake server # サーバが起動されます(ポート 53330/tcp を LISTEN) | |
: | |
$ rake load | |
: # DCG がロードされて応答メッセージがたくさん出ます |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ pry -r drb # drb を require する | |
: | |
[1] pry(main)> DRb.start_service # DRbサービスを起動する | |
=> ... | |
: | |
[2] pry(main)> tr = DRbObject.new_with_uri 'druby://:53333' # リモートオブジェクト取得 | |
=> ... | |
[3] pry(main)> tr.jp "time flies like an arrow" | |
=> ["時間はひとつの矢のように飛ぶ", "時の蝿はひとつの矢を好む", "蝿をひとつの矢のように拍子を合わせる"] | |
: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tr = DRbObject.new_with_uri 'druby://192.168.1.101:53333' | |
^^^^^^^^^^^^^ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: テスト実行直前 | |
$ sudo ufw disable # 私は ufw を使っています | |
ファイアウォールを無効にし、システム起動時にも無効にします | |
: テスト実行終了後 | |
$ sudo ufw enable | |
ファイアウォールはアクティブかつシステムの起動時に有効化されます。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[4] pry(main)> tr.proxy.q "mortal(Who)" # 問い合わせ | |
=> "[mortal(plato)]" # この結果は、既に事実・規則が登録済の場合 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ps aul | grep -w [r]ake # rake のプロセス情報を抽出表示 | |
$ pidof rake # rake のプロセスの PID 表示 (PID は複数表示がありえる) | |
$ kill 12345 # PID 12345(例) のプロセスを kill | |
$ killall rake # (注) この場合、起動している全ての rake プロセスが kill されます |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: | |
: racc で prolog_parser.ry から prolog_parser.rb をコンパイル | |
: | |
$ racc -g -o prolog_parser.rb prolog_parser.ry |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: ポート 53330/tcp が LISTEN されているか確認 | |
$ ss -tl | grep -w 53330 | |
tcp LISTEN 0 128 *:53330 *:* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ rake "jp[time flies like an arrow]" # 和訳。 結果は以下の3つ | |
時間はひとつの矢のように飛ぶ | |
時の蝿はひとつの矢を好む | |
蝿をひとつの矢のように拍子を合わせる | |
$ rake "en[時間はひとつの矢のように飛ぶ]" # 英訳(1) | |
time flies like an arrow | |
$ rake "en[時の蝿はひとつの矢を好む]" # 英訳(2) | |
time flies like an arrow | |
$ rake "en[蝿をひとつの矢のように拍子を合わせる]" # 英語(3) | |
time flies like an arrow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ps aul | grep -w [s]wipl # swipl のプロセス情報を抽出表示 | |
$ pidof swipl # swipl のプロセスの PID 表示 (PID は複数表示がありえる) | |
$ kill 12345 # PID 12345(例) のプロセスを kill | |
$ killall swipl # (注) この場合、起動している全ての swipl プロセスが kill されます |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ rake "jp[arrow flies]" | |
矢は飛ぶ | |
$ rake "en[時の矢]" | |
time arrow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: rake server | |
: rake load | |
: ... の後に、 | |
$ pry -r prolog_translator # prolog_translator を require する | |
: | |
[1] pry(main)> cd Prolog::Translator | |
[2] pry(Prolog::Translator):1> jp "time flies like an arrow" | |
=> ["時間はひとつの矢のように飛ぶ", "時の蝿はひとつの矢を好む", "蝿をひとつの矢のように拍子を合わせる"] | |
[3] pry(Prolog::Translator):1> en "時間はひとつの矢のように飛ぶ" | |
=> ["time flies like an arrow"] | |
: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[16] pry(Prolog::Translator):1> cd - # main に戻って | |
[17] pry(main)> cd Prolog::Proxy # Proxy に cd して | |
[18] pry(Prolog::Proxy):1> ins "person(plato)" # 事実の登録 | |
=> "[assert(person(plato))]" | |
[19] pry(Prolog::Proxy):1> ins "mortal(X) :- person(X)" # 規則の登録 | |
=> "[assert((mortal(_G61):-person(_G61)))]" | |
[20] pry(Prolog::Proxy):1> q "mortal(Who)" # 問い合わせ | |
=> "[mortal(plato)]" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[1] pry(main)> cd Prolog::Translator | |
[2] pry(Prolog::Translator):1> tr = new | |
=> ... | |
[3] pry(Prolog::Translator):1> tr.en "時の蝿はひとつの矢を好む" | |
=> ["time flies like an arrow"] | |
[4] pry(Prolog::Translator):1> tr.proxy.ins "person(socrates)" | |
=> "[assert(person(socrates))]" | |
[5] pry(Prolog::Translator):1> tr.proxy.q "person(Who)" | |
=> "[person(socrates)]" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
: rake server | |
: rake load | |
: ... の後に、 | |
$ rake daemon # drb デーモンが起動する |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'drb' | |
require 'socket' | |
require 'timeout' | |
require 'resolv-replace' | |
require 'prolog_parser' | |
module Prolog | |
def self.connect(*args, &block) | |
Proxy.new(*args, &block) | |
end | |
class Proxy | |
include DRb::DRbUndumped | |
DRB_URI = 'druby://:53331' | |
PORT = 53330 | |
HOST = 'localhost' | |
ENCODING = 'EUC-JP' # SWI-Prolog向け設定 | |
class << self | |
def inquire(query, *args, &enc) | |
new(*args).inquire(query, &enc) | |
end | |
alias q inquire | |
def insert(clause, *args, &enc) | |
new(*args).insert(clause, &enc) | |
end | |
alias ins insert | |
def load(files, dir=nil, *args, &enc) | |
new(*args).load(files, dir) | |
end | |
def remove(clause, *args, &enc) | |
new(*args).remove(clause, &enc) | |
end | |
def drb(uri=nil, *args, &block) | |
DRb.start_service (uri || DRB_URI), new(*args, &block) | |
DRb.thread.join | |
end | |
def daemon(*args, &block) | |
Process.daemon | |
drb *args, &block | |
end | |
end | |
attr_writer :port, :host, :encoding | |
attr_accessor :tmout | |
def port ; @port ||= PORT ; end | |
def host ; @host ||= HOST ; end | |
def encoding ; @encoding ||= ENCODING ; end | |
def initialize(port:nil, host:nil, encoding:nil, &block) | |
tap {|my| my.host, my.port, my.encoding = | |
host, port, encoding } | |
instance_eval(&block) if block | |
end | |
# Prolog サーバのデータベースに節を問い合わせをする | |
def inquire(query=nil, ruby:nil, &enc) | |
query = Prolog.to_prolog(ruby) if ruby | |
timeout(tmout) do | |
TCPSocket.open(host, port) do |s| | |
s.puts "#{enc_to(query, &enc)}." | |
enc_from(s.gets, &enc) | |
end | |
end | |
end | |
alias q inquire | |
# Prolog サーバのデータベースに節を追加する | |
def insert(clause=nil, ruby:nil, &enc) | |
clause = Prolog.to_prolog(ruby) if ruby | |
query = dcg?(clause) ? "dcg_translate_rule((#{clause}),X),assert(X)" | |
: "assert((#{clause}))" | |
inquire(query, &enc) | |
end | |
alias ins insert | |
# Prolog サーバのデータベースにファイルの内容(節)を追加する | |
def load(files, dir=nil) | |
files.map{|fname| File.join(dir || '.', fname)}.each do |file| | |
Prolog.parse(file:file).map {|term| insert(ruby:term) } | |
end | |
end | |
# Prolog サーバのデータベースから節を削除する | |
def remove(clause=nil, ruby:nil, &enc) | |
clause = Prolog.to_prolog(ruby) if ruby | |
query = dcg?(clause) ? "dcg_translate_rule((#{clause}),X),retract(X)" | |
: "retract((#{clause}))" | |
inquire(query, &enc) | |
end | |
private | |
def enc_to(s, &block) | |
enc = block ? block.() : encoding | |
(s && enc) ? s.encode(enc) : s | |
end | |
def enc_from(s, &block) | |
enc = block ? block.() : encoding | |
(s && enc) ? s.encode('UTF-8', enc) : s | |
end | |
def dcg?(clause) | |
# TODO: もう少し厳密な判定に | |
clause =~ /-->/ | |
end | |
end | |
end | |
if __FILE__ == $0 | |
# | |
# $ ruby prolog_proxy.rb --drb [options] [URI] # drb server | |
# | |
# $ ruby prolog_proxy.rb --drb --daemon [options] [URI] # drb server (daemon) | |
# | |
require 'ostruct' | |
require 'optparse' | |
opt = OpenStruct.new ARGV.getopts '', 'drb', 'daemon', | |
'port:', 'host:', 'encoding:' | |
uri = ARGV.shift | |
if opt.drb | |
Prolog::Proxy.send(opt.daemon ? :daemon : :drb, uri) do |my| | |
my.port = opt.port if opt.port | |
my.host = opt.host if opt.host | |
my.encoding = opt.encoding if opt.encoding | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'drb' | |
require 'natto' | |
require 'prolog_proxy' | |
module Prolog | |
class Translator | |
include DRb::DRbUndumped | |
DRB_URI = 'druby://:53333' | |
DCG_FILES = %w(dcg-en-grammar.pro dcg-en-vocabulary.pro | |
dcg-jp-grammar.pro dcg-jp-vocabulary.pro) | |
class << self | |
def load(files=nil, dir=nil, *args) | |
new(*args).load(files, dir) | |
end | |
def jp(sentence, *args) | |
new(*args).jp(sentence) | |
end | |
def en(sentence, *args) | |
new(*args).en(sentence) | |
end | |
def drb(uri=nil, *args, &block) | |
DRb.start_service (uri || DRB_URI), new(*args, &block) | |
DRb.thread.join | |
end | |
def daemon(*args, &block) | |
Process.daemon | |
drb *args, &block | |
end | |
end | |
attr_writer :proxy, :port, :host, :encoding | |
def port ; @port ||= Prolog::Proxy::PORT ; end | |
def host ; @host ||= Prolog::Proxy::HOST ; end | |
def encoding ; @encoding ||= Prolog::Proxy::ENCODING ; end | |
def proxy | |
@proxy ||= Prolog::Proxy.new(port:port, host:host, encoding:encoding) | |
end | |
def initialize(proxy:nil, port:nil, host:nil, encoding:nil, &block) | |
tap {|my| my.proxy, my.host, my.port, my.encoding = | |
proxy, host, port, encoding } | |
instance_eval(&block) if block | |
end | |
# DCG ファイルのロード | |
def load(files=nil, dir=nil) | |
files = DCG_FILES if !files || files.empty? | |
Prolog::Proxy.load(files, dir) | |
end | |
# 翻訳: 英語 -> 日本語 | |
def jp(sentence) | |
ss = sentence.split.map(&:to_sym) | |
query = {translate:[var(:J), ss, var()]} # 述語 translate/3 | |
Prolog.to_ruby(proxy.inquire(ruby:query)).map{|pred| arg(pred,0).join } | |
end | |
# 翻訳: 日本語 -> 英語 | |
def en(sentence) | |
ss = jsplit(sentence).map(&:to_sym) | |
query = {translate:[ss, var(:E), var()]} # 述語 translate/3 | |
Prolog.to_ruby(proxy.inquire(ruby:query)).map{|pred| arg(pred,1) * ' '} | |
end | |
private | |
def var(sym=:_) | |
{ nil => sym.to_sym } | |
end | |
def arg(pred, n) | |
pred.values.first[n] | |
end | |
def jsplit(s) | |
ss = [] | |
Natto::MeCab.new.parse(s) {|n| ss << n.surface } | |
ss.compact | |
end | |
end | |
end | |
if __FILE__ == $0 | |
# | |
# $ ruby prolog_translator.rb --drb [options] [URI] # drb server | |
# | |
# $ ruby prolog_translator.rb --drb --daemon [options] [URI] # drb daemon | |
# | |
require 'ostruct' | |
require 'optparse' | |
opt = OpenStruct.new ARGV.getopts '', 'drb', 'daemon', | |
'port:', 'host:', 'encoding:' | |
uri = ARGV.shift | |
if opt.drb | |
Prolog::Translator.send(opt.daemon ? :daemon : :drb, uri) do |my| | |
my.port = opt.port if opt.port | |
my.host = opt.host if opt.host | |
my.encoding = opt.encoding if opt.encoding | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'prolog_translator' | |
SERVER = 'server.pro' | |
PORT = Prolog::Proxy::PORT | |
# | |
# Prolog サーバへの起動と設定 | |
# | |
desc 'Prolog サーバの起動' | |
task:server, [:port, :server_program] do |t, args| | |
port = args[:port] || PORT | |
server = args[:server_program] || SERVER | |
Process.spawn "swipl -l #{server} -g 'create_server(#{port}).'" | |
end | |
desc 'ファイルのロード' | |
task:load, [:files] do |t, args| | |
files = (args[:files]||'').split(',') | |
Prolog::Translator.load files | |
end | |
desc 'drb デーモンとして起動' | |
task:daemon, [:drb_uri, :port, :host, :encoding] do |t, args| | |
Prolog::Translator.daemon(args[:drb_uri]) do |my| | |
my.port = args[:port] if args[:port] | |
my.host = args[:host] if args[:host] | |
my.encoding = args[:encoding] if args[:encoding] | |
end | |
end | |
desc '翻訳: 英語 -> 日本語' | |
task:jp, [:sentence] do |t, args| | |
Prolog::Translator.jp(args[:sentence] || '').each {|j| puts j } | |
end | |
desc '翻訳: 日本語 -> 英語' | |
task:en, [:sentence] do |t, args| | |
Prolog::Translator.en(args[:sentence] || '').each {|e| puts e } | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create_server(Port) :- | |
tcp_socket(Socket), | |
tcp_setopt(Socket, reuseaddr), | |
tcp_bind(Socket, Port), | |
tcp_listen(Socket, 5), | |
tcp_open_socket(Socket, AcceptFd, _), | |
dispatch(AcceptFd). | |
dispatch(AcceptFd) :- | |
tcp_accept(AcceptFd, Socket, Peer), | |
thread_create(process_client(Socket, Peer), _, [detached(true)]), | |
dispatch(AcceptFd). | |
process_client(Socket, _) :- | |
setup_call_cleanup( tcp_open_socket(Socket, In, Out), | |
handle_service(In, Out), | |
close_connection(In, Out)). | |
close_connection(In, Out) :- | |
close(In, [force(true)]), | |
close(Out, [force(true)]). | |
handle_service(In, Out) :- | |
read(In, Chars), | |
findall(Chars, Chars, L), | |
write(Out, L), | |
writeln(L). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment