GNU Prolog を Ubuntu 18.04 にインストールした

GNU PrologUbuntu 18.04 にインストールする際に苦労したので、メモとして残しておく。

困りごと

まず最初に、

sudo apt install gprolog

としてgprolog 1.4.5-4.1をインストールした。

しかし、こうしてインストールした gprolog は、たとえば

likes(taro, sushi).
likes(bob, sushi).
likes(john, udon).

friend(X, Y) :- \+(X=Y), likes(X, Z), likes(Y, Z).

friends.plに書き込み、gprolog 上で

['friends.pl'].
friend(taro, bob).

と入力すると、本来はyesという出力があるべきなのに、エラーが発生した。1

解決

まず最初に、gprolog をaptでアンインストールした。

そして、以下のページから gprolog-1.4.5.tar.gz をダウンロードしてインストールした。
なお、configureには特別なオプションは必要なく、INSTALLに書いてある通りにしてインストールできた。
http://www.gprolog.org/


  1. この例は 7つの言語7つの世界 第1版 p.75-76 の内容を少し改変したものだ。

素数番目の素数 / 素数番目の素数番目の素数

素数番目の素数番目の素数というのが気になって、 とりあえずHaskellで実装してみることにした。

素数, 素数番目の素数

素数番目の素数を求めるとき、最初に素数列を求めたい。 素数列を求める一般的な式は見つかっていないから、 数列 \left\{ b_n \right\} を、 b_n = n+1 (初項は2)として  b_nから素数だけを抜き出すという方法で 素数 \left\{a_n\right\}を求めることにした。

primes :: [Int]
primes = filter isPrime [2..]

isPrime n = all (not.(isFactor n)) [2..intsqrt n]
    where
        intsqrt = floor.sqrt.fromIntegral
        isFactor n m = (n `mod` m) == 0

これで、primesはIntの最大値を超えない限り素数列を吐いてくれるようになった。 素数番目の素数からなる数列、つまり a_{a_n}map (\n -> primes!!n) primes と書ける。1

とりあえず、素数列と素数番目の素数の数列を適当な変数に束縛する。

main :: IO ()
main = do
    let prime = primes
    let primeprime = map (\n -> prime!!(n-1)) prime
    putStrLn $ "100個の素数   : " ++ (show $ take 100 prime)
    putStrLn $ "素数番目の素数: " ++ (show $ take 100 primeprime)

primes :: [Int]
primes = filter isPrime [2..]

isPrime n = all (not.(isFactor n)) [2..intsqrt n]
    where
        intsqrt = floor.sqrt.fromIntegral
        isFactor n m = (n `mod` m) == 0
素数番目の素数番目の素数

ここで、少し困ったことになる。素数番目の素数番目の素数というのをどう表すべきかだ。

素数列から素数番目の素数番目の数だけを取り出すべきなのか、素数番目の素数の数列から素数番目の数を取り出すべきなのか。 つまり、map (\n -> prime!!n) primeprimeなのかmap (\n -> primeprime!!n) primeなのかということだ。

とりあえず、両方実装してみることにする。

main :: IO ()
main = do
    let prime = primes
    let primeprime = map (\n -> prime!!(n-1)) prime
    let primeprimeprime = map (\n -> prime!!(n-1)) primeprime
    let primeprimeprime2 = map (\n -> primeprime!!(n-1)) prime
    putStrLn $ "100個の素数               : " ++ (show $ take 100 prime)
    putStrLn $ "素数番目の素数            : " ++ (show $ take 100 primeprime)
    putStrLn $ "(素数番目の素数)番目の素数: " ++ (show $ take 100 primeprimeprime)
    putStrLn $ "素数番目の(素数番目の素数): " ++ (show $ take 100 primeprimeprime2)

primes :: [Int]
primes = filter isPrime [2..]

isPrime n = all (not.(isFactor n)) [2..intsqrt n]
    where
        intsqrt = floor.sqrt.fromIntegral
        isFactor n m = (n `mod` m) == 0

さて、これを実行した結果だが、 primeprimeprimeprimeprimeprime2は、少なくとも100項目までは同じ値になった。

10項目までの結果は以下の通り。

10個の素数               : [2,3,5,7,11,13,17,19,23,29]
素数番目の素数            : [3,5,11,17,31,41,59,67,83,109]
(素数番目の素数)番目の素数: [5,11,31,59,127,179,277,331,431,599]
素数番目の(素数番目の素数): [5,11,31,59,127,179,277,331,431,599]
素数番目の素数番目の素数 is 何

素数番目の素数番目の素数というのをもう少しはっきり書く。

まず、素数番目の素数だが、先程も書いた通り、 素数 a_nに対して a_{a_n}素数番目の素数になる。

そして、(素数番目の素数)番目の素数からなる数列というのは、  a_{(a_{a_n})}という数列、 つまり a_{a_{a_n}}というわけだ。

素数番目の(素数番目の素数)からなる数列というのも、  a_{a_{(a_n)}}という数列で、  a_{a_{a_n}}になる。

ここから、primeprimeprimeprimeprimeprime2も同じ数列のことを表していたということが分かった。

ところで、今回の話では a_n素数列であるということにしたが、  a_nが数列であることに起因する性質しか使っていないので、  a_nのすべての項が数列の添字として使うことができる数(つまり自然数)ならばこの性質は成り立つ。


  1. ちなみに、素数番目の素数のことをスーパー素数と呼ぶらしい。