猫野詩梨帳

かわいいはかしこい

Neovim をターミナル環境として使用するときとかのメモとか

Neovim にはターミナルエミュレータが埋め込まれており,:terminal 等で起動することができる.

じゃあ最初から端末の代わりに Neovim 開いちゃえばいいじゃんということで,それをもっと便利にするためのメモ.

便利なプラグイン

基本的に新しい端末を開かないで,新しいバッファを開くようにすると楽なため,バッファに関するプラグインを入れておくと便利.

itchyny/lightline

ステータスラインとタブラインがかっこよくなるやつ.

taohex/lightline-buffer

lightline のプラグインで,タブラインにバッファを表示する.タブよりバッファ使う人用.

README にある通り init.vim に以下のような設定が必要.

let g:lightline = {
\   'tabline': {
\     'left': [ [ 'bufferinfo' ], [ 'bufferbefore', 'buffercurrent', 'bufferafter' ], ],
\     'right': [ [ 'close' ], ],
\   },
\   'component_expand': {
\     'buffercurrent': 'lightline#buffer#buffercurrent2',
\   },
\   'component_type': {
\     'buffercurrent': 'tabsel',
\   },
\   'component_function': {
\     'bufferbefore': 'lightline#buffer#bufferbefore',
\     'bufferafter': 'lightline#buffer#bufferafter',
\     'bufferinfo': 'lightline#buffer#bufferinfo',
\   },
\ }

'close' はなんのためにあるのかよくわかっていない.

mhinz/vim-sayonara

:Sayonara すると現在のバッファを閉じ,最後の1つだった場合ウィンドウを閉じる(たぶん).ウィンドウを閉じたくない場合はなぜか :Sayonara!.しめやかに爆発四散.

:bdelete だとバッファが最後の1つだった場合ウィンドウを閉じてくれない.ウィンドウを閉じたい場合はこれを使うと便利かもだ.

init.vim に書いておくと便利な設定

左右矢印キーでのバッファ移動

矢印キーに,バッファを移動する :bnext, :bprev を割り当てる.お好みでノーマルモード以外にも割り当てたり,Alt + 矢印にしたりとか.

nnoremap <Left>  :<C-u>bprev<CR>
nnoremap <Right> :<C-u>bnext<CR>

ターミナルモード中に ESC でコマンドモードに戻る

<C-\><C-n> なんてどう考えても打っていられないので.

tnoremap <silent> <ESC> <C-\><C-n>

新しいターミナルを開く

:enew で新しいバッファを開いてから :terminal でもいいんだけど,一発で開けると便利かもだ.

command! Tnew :enew | :terminal

これで :Tnew で新しいターミナルが新しいバッファに開くようになる.

また :Term:VTerm で水平・垂直分割して新しいターミナルバッファを開く vimlab/split-term.vim のようなプラグインもある.お好みで.

Sayonara

上記プラグイン:Sayonara:Q にマップ.

command! -bar -nargs=* -complete=file -range=% -bang W
  \ <line1>,<line2>write<bang> <args>
command! -bar -nargs=* -complete=file -range=% -bang Write
  \ <line1>,<line2>write<bang> <args>
command! -bar -nargs=* -complete=file -range=% -bang Wq
  \ <line1>,<line2>write<bang> <args> | :Sayonara
command! -bar -nargs=* -complete=file -range=% -bang WQ
  \ <line1>,<line2>write<bang> <args> | :Sayonara

command! -bar -bang Wqall wqall<bang>
command! -bar -bang WQall wqall<bang>

command! -bar Q :Sayonara
command! -bar Quit :Sayonara
command! -bar -bang Qall qall<bang>

便利なツール

mhinz/neovim-remote

要 Python3.pip3 でインストールする.

ターミナルモードで nvim すると新しい nvim が開いてしまう.これを入れると nvr で現在の nvim 中でファイルを開けるようになる.なんでかはよくわからん.

alias :e=nvr とかしておくとターミナルモードで :e text.txt とかできて便利かもだ.

Dock に追加 (Mac)

Mac で Dock 上から起動するためには一工夫必要.色々な方法がありそうだが今回は AppleScript を利用する.

Automator で「アプリケーション」を選択し,「AppleScript を実行」をダブルクリックし以下のように記述する.

on run {input, parameters}
    set cmd to "nvim -c :terminal; exit" -- 実行するコマンド

    tell application "Terminal"
        -- ターミナルが起動していない場合は launch で起動する
        -- launch しないと暗黙的に run され,ウィンドウが1つ開いてしまう
        launch
        activate -- 最前面に表示

        -- ウィンドウが開いていない場合のみコマンドを実行する
        if number of windows < 1 then
            -- Terminal は run/reopen 命令を受けると
            -- 新規ウィンドウがなければ新しく作成する
            reopen
            -- 1番めのウィンドウでコマンドを実行
            do script cmd in window 1
        end if

    end tell
end run

これを保存すると .app ファイル(フォルダ)が作成されるので,Dock に追加できる.ついでにアイコンも Neovim のアイコンにするとかっこいい(?)

できてないこと

  • バッファが1つのときにターミナルモードで exit しても終了しない.
  • 履歴に nvim -c :terminal; exit が残る
  • クリップボード連携
  • シェルのカレントディレクトリと nvim のカレントディレクトリがあるのでなんかややこしい.
  • :Tnew で開くシェルが nvim のカレントディレクトリで開いてしまう

感想

結構頑張って設定しないとあんまり便利じゃなさそう.

参考

neovimのterminal emulatorが便利すぎた - tsub’s blog

NeoVimを端末として使うためにしたこと - Qiita

gRPC with FlatBuffers

gRPC は Google が開発している RPC(リモートプロシージャコール)フレームワークなんですけど,デフォルトだと同じく Google 製の Protocol Buffer (Protobuf) というシリアライズフォーマットを用います.

Protobuf についてはこれをみてね↓

qiita.com

ただ gRPC 自体は JSON とか XML とか他のフォーマットにも拡張できるようにデザインされているということで,例えばこれもまた Google 製の FlatBuffers というシリアライズフォーマットがあるんですけど,これも使えます.

Flatbuffers はめちゃ速いらしいんですけれど使うのがちょっと難しいです.

あんまり例とかも見ないのでちょっと簡単な例を作ってみました.

github.com

データ定義はこんな感じで

namespace Quiz;

table QuizTable {
  question:string;
  answer:bool;
}

table QuizRequest {
  quizNumber:int;
}

rpc_service QuizService {
  FetchQuiz(QuizRequest): QuizTable;
}

サーバーに QuizRequest としてクイズ番号を送ると対応する QuizTable を返してくれる,みたいな感じになってます.超シンプル!

FlatBuffers の(デ)シリアライズを行っているのは util/builder/builder.go です.たとえば

func QuizTableBuilder(q *util.Quiz) *flatbuffers.Builder {
    builder := flatbuffers.NewBuilder(0)
    question := builder.CreateString(q.Question)
    answer := util.Bool2Byte(q.Answer)

    quizAPI.QuizTableStart(builder)
    quizAPI.QuizTableAddQuestion(builder, question)
    quizAPI.QuizTableAddAnswer(builder, answer)
    qtOfs := quizAPI.QuizTableEnd(builder)

    builder.Finish(qtOfs)
    return builder
}

まず builder を作って,そこにひたすらデータを詰めていきます.今回は QuizTable を詰めるだけですが.テーブルを詰めるときは XXXStart ~ XXXEnd の間で中身を詰めます.

そして実際に gRPC でクライアント / サーバ処理を行っているのが client/main.go, server/main.go です.このあたりはほぼ gRPC with Protobuf と同じですね.違いはオプションとして grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}) を渡しているくらいです.

現状クライアントはただクイズデータをとってきて表示するだけですが,実際にクイズとして遊べるようにしてみたりすると面白いと思います.

感想

みんなクイズのゲーム (QMA) やろう!

Haskell でブロックチェーンのような構造を考える

Haskell でブロックチェーンのようなデータ構造が作れないか考えた時のメモ.ほぼお遊び.

Hashable 型クラス

まず次のようなデータ型を考える.

data MyHash a b

これはハッシュ方法を表すデータ型である.ハッシュ方法は,Hashable 型クラスの提供するメソッド hash を実装することによって表すことにする.

{-# LANGUAGE MultiParamTypeClasses #-}

class Hashable a b h where
  hash :: h -> a -> b

MultiParamTypeClasses 拡張は,このように引数が複数ある (a, b, h) 型クラスを定義することを許す.

h は,ただハッシュ方法を表す型を区別するためだけのものである.本当は単に hash :: a -> b としたいところだが,これだと h の型を指定することができない.

さて今 MyHash String ByteString について考える.これは String から ByteString へのハッシュ方法を表している.hash の実装は,簡単のため単に reverse して pack するだけとする(果たしてハッシュと言えるのか).

{-# LANGUAGE FlexibleInstances #-}

import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8
 
instance Hashable String ByteString (MyHash String ByteString) where
  hash _ s = BL8.pack (reverse s)

FlexibleInstances 拡張は,このように型コンストラクタ (MyHash) に具体型 (String, ByteString) を入れた型に対してのインスタンス宣言などを許す.

実際に hash を試してみる.

> :t hash
hash :: Hashable a b h => h -> a -> b
> let p = undefined :: MyHash String ByteString
> hash p "data" :: ByteString
"atad"

hash の 1 つめの引数は,単に型を指定するだけのものである.そのためここでは p = undefinedMyHash String ByteString という型をつけて渡している.undefined を使わなくて良い方法を後に示す.

p の型は MyHash String ByteString であるから,hash p "data" の型は ByteString に決定しそうに見える.しかし実際には決まらない.

> let p = undefined :: MyHash String ByteString
> hash p "data"

<interactive>:1:1: error:
    • Non type-variable argument
        in the constraint: Hashable [Char] b (MyHash String ByteString)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall b. Hashable [Char] b (MyHash String ByteString) => b

もしかしたら instance Hashable String Int (MyHash String ByteString) のようなインスタンスがあるかもしれないからである.実際このようなインスタンス宣言は有効である.

そこで,Hashable 型クラスに次のような関数従属を追加する.

{-# LANGUAGE FunctionalDependencies #-}

class Hashable a b h | h -> a, h -> b where
  hash :: h -> a -> b

FunctionalDependencies 拡張は,関数従属を記述することを許す.関数従属は,| に続いて a -> b のように記述する.これは,a から b がただ一つ定まるということを主張する.

今回は,型 h (例えば MyHash String ByteString) から a (String), b (ByteString) が定まるという従属関係をクラスに追加している.

> let p = undefined :: MyHash String ByteString
> hash p "data"
"atad"

h から a, b が一意に定まるということを主張してしまったので,もはや MyHash String ByteString について ab が異なるインスタンスを定義することはできない.

例えば,instance Hashable String Int (MyHash String ByteString) を追加すると,conflict していると文句を言われる.

Main.hs:19:10: error:
    Functional dependencies conflict between instance declarations:
      instance Hashable String ByteString (MyHash String ByteString)
        -- Defined at Main.hs:19:10
      instance Hashable String Int (MyHash String ByteString)
        -- Defined at Main.hs:22:10

もちろん instance Hashable String ByteString (MyHash String ByteString) を削除して instance Hashable String Int (MyHash String ByteString) に変えることは可能である.しかし Int を返す hash を定義したいならば instance Hashable String Int (MyHash String Int) とするべきである.

Data.Proxy を利用する

hash の 1 つめの引数に型をつけた undefined を渡すのはあまり気持ちよくない.そこで base パッケージ (>= 4.7.0.0) の Data.Proxy にある Proxy を用いる.

Proxy は単に次のような型である.

data Proxy t = Proxy

ある型 tProxy で包むと,Proxy という値コンストラクタで Proxy t 型の値 Proxy が生成できるようになる.それだけである.

> :m + Data.Proxy
> Proxy :: Proxy Int
Proxy
> Proxy :: Proxy (MyHash String ByteString)
Proxy

これを用いて Hashable クラスを次のように変更する.

import Data.Proxy (Proxy(..))

class Hashable a b h | h -> a, h -> b where
  hash :: Proxy h -> a -> b

すると hash は次のように使える.

> let p = Proxy :: Proxy (MyHash String ByteString)
> hash p "data"
"atad"

いちいち Proxy をつけるのは面倒だが,undefined を使う必要がなくなった.

ここまでのプログラム
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8

import Data.Proxy (Proxy(..))

data MyHash a b

class Hashable a b h | h -> a, h -> b where
  hash :: Proxy h -> a -> b

instance Hashable String ByteString (MyHash String ByteString) where
  hash _ s = BL8.pack (reverse s)

Blockchain データ型

本題.ブロックチェーンとは,分散型台帳(データベース)の仕組みの一つである.この語は広義的であるが,ここでは単純に次のようなリストを表すということにする.

f:id:CyLomw:20170421202538p:plain

すなわち,リストの各要素(ブロック)が 1 つ前の要素(ブロック)のハッシュ値を持つようなリストである.要素を追加するときには,1つ前の要素のハッシュ値を計算し持たせる.リスト中の要素を変更する場合は,それ以降のすべての要素についてハッシュを計算し直さなければならない.

ビットコインなどのシステムでは,ブロックを作成するために時間のかかる計算を行わなければならないようにして,リスト中の要素の改竄を防いでいる.

ここでのブロックチェーンは単にリストであるので,次のように表すことができる.ただし,データはリストの先頭に追加していくものとする.

newtype Blockchain h b a = Blockchain [(a, b)]
  deriving (Show)

a は保存するデータの型,bハッシュ値の型,h はハッシュ方法を表す型とする.

リストの要素の型は (a, b) である.これをハッシュして b にしなければならないため,ハッシュ関数の型は (a, b) -> b である.

今回は aString, bByteString とする.h については MyHash を使い回すとすると,hash の型は Proxy ... -> (String, ByteString) -> ByteString でなければならないため,インスタンス定義を次のように変更する1

instance Hashable (String, ByteString) ByteString
    (MyHash (String, ByteString) ByteString) where
  hash _ (s, bs) = (BL8.pack $ reverse s) `BL.append` bs

今回も単純に reverse して pack して append するだけとした.

Blockchain 値コンストラクタは非公開にするであろうから,最初のブロックを作成する関数 genesis を作成する.

{-# LANGUAGE FlexibleContexts #-}

genesis :: Hashable (a, b) b h => a -> b -> Blockchain h b a
genesis x y = Blockchain [(x, y)]

FlexibleContexts 拡張は型クラス制約の制限を緩くする.この拡張がないと Hashable (a, b) b h => という制約は記述できない.

次に,ブロックを追加する関数 bcons を作成する.

bcons :: Hashable (a, b) b h
      => a -> Blockchain h b a -> Blockchain h b a
bcons x (Blockchain xs) = Blockchain $ (x, hashed):xs
  where hashed = hash (Proxy :: Proxy h) (head xs)

これはコンパイル通らない.これについては,Scoped type variablesが必要になるとき - maoeのブログに詳しい.よくわからない場合は,関数の型宣言内で使用した型変数 (a, b, h) のスコープ(寿命)はその型宣言内だけであり,関数本体では使えない,と考えても良いかもしれない.

ScopedTypeVariables 拡張を用いると型変数のスコープを関数本体まで持ち込むことができる.ただし,明示的に forall を記述する必要がある.

{-# LANGUAGE ScopedTypeVariables #-}

bcons :: forall a b h. Hashable (a, b) b h
      => a -> Blockchain h b a -> Blockchain h b a
bcons x (Blockchain xs) = Blockchain $ (x, hashed):xs
  where hashed = hash (Proxy :: Proxy h) (head xs)

ところで,xs が空リストの場合 head が失敗するためこのままだと危険である.ただ,Blockchain 値コンストラクタを非公開にすれば,最小のブロックチェーンの作成は genesis のみによって行われるため head が失敗することは避けられる.もう一つの方法は NonEmpty を使うことである.

ここまでのプログラム
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8

import Data.Proxy (Proxy(..))

data MyHash a b

class Hashable a b h | h -> a, h -> b where
  hash :: Proxy h -> a -> b

instance Hashable (String, ByteString) ByteString
    (MyHash (String, ByteString) ByteString) where
  hash _ (s, bs) = (BL8.pack $ reverse s) `BL.append` bs

newtype Blockchain h b a = Blockchain [(a, b)]
  deriving (Show)

genesis :: Hashable (a, b) b h => a -> b -> Blockchain h b a
genesis x y = Blockchain [(x, y)]

bcons :: forall a b h. Hashable (a, b) b h
      => a -> Blockchain h b a -> Blockchain h b a
bcons x (Blockchain xs) = Blockchain $ (x, hashed):xs
  where hashed = hash (Proxy :: Proxy h) (head xs)

NonEmpty リストを利用する

NonEmpty リストは名前の通り空でないリストである.そのため head は常に安全となる.NonEmpty リストは base パッケージ 4.9.0.0 で追加された.

NonEmpty リストは次のように使うことができる.

> :m + Data.List.Nonempty
> 1 :| []
1 :| []
> 2 <| (1 :| [])
2 :| [1]
> 3 <| (2 :| [1])
3 :| [2, 1]
> Data.List.NonEmpty.head $ 3 <| (2 :| [1])
3
> toList $ 3 :| [2, 1]
[3,2,1]

即ち NonEmpty リストは 頭 :| [尻尾] という構造をしている.最小の(長さ1の)リストは 頭 :| [] である.リストの先頭への追加は <| 演算子(あるいは cons)で行う.

これを用いるとプログラム(の一部)は次のように書き換えられる.

import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.List.NonEmpty as NE

newtype Blockchain h b a = Blockchain (NonEmpty (a, b))
  deriving (Show)

genesis :: Hashable (a, b) b h => a -> b -> Blockchain h b a
genesis x y = Blockchain $ (x, y) :| []

bcons :: forall a b h. Hashable (a, b) b h
      => a -> Blockchain h b a -> Blockchain h b a
bcons x (Blockchain xs) = Blockchain $ (x, hashed) <| xs
  where hashed = hash (Proxy :: Proxy h) (NE.head xs)

テスト

実際にブロックチェーンを構築してみる.

最初に次のような別名を定義しておくことをお勧めする.

type BC hc b a = Blockchain (hc (a, b) b) b a

genesisbcons を用いてブロックチェーンが構築できることを確かめる.

test1 :: BC MyHash ByteString String
test1 = genesis "genesis-block" BL.empty

test2 :: BC MyHash ByteString String
test2 = bcons "2nd-block" test1

test3 :: BC MyHash ByteString String
test3 = bcons "3rd-block" test2
> test3
Blockchain (("3rd-block","kcolb-dn2kcolb-siseneg")
  :| [("2nd-block","kcolb-siseneg"),("genesis-block","")])

2 番目のブロックの文字列 (“2nd-block”) を変更したとすると,3 番目のブロックのハッシュ値も変更しなければならないことがわかる.

ブロックチェーンをチェックする関数 check を作成してみよう.

import Data.Foldable (foldrM)
import Data.Maybe (isJust)

check :: forall a b h. (Hashable (a, b) b h, Eq b)
      => Blockchain h b a -> b -> Bool
check (Blockchain xs) initHash = isJust $ foldrM checkf initHash xs
    where checkf (x, y) prevHash
            | prevHash == y = Just $ hash (Proxy :: Proxy h) (x, y)
            | otherwise     = Nothing

checkfoldrM を用いてリストの右からハッシュをチェックする.即ち,1 つ前のデータのハッシュと現在のデータの保持しているハッシュ値が等しいかどうか (prevHash == y) を順にチェックしていく.foldrMfoldr の変種で,モナドが扱える.ここでは Maybe モナドを利用し,不正な値があった場合は Nothing を出すようにしている.

> check test3 BL.empty
True
> check test3 (BL8.pack "illegal initial hash")
False

また,ブロックチェーンを変更する関数は次のように作成できる.

import qualified Data.Foldable as FD
import qualified Data.Traversable as TS

instance Foldable (Blockchain h b) where
  foldr f z (Blockchain xs) = foldr (f. fst) z xs

mapAccumR :: forall a b c d h k. (Hashable (a, b) b h, Hashable (d, b) b k)
          => (c -> a -> (c, d)) -> c -> Blockchain h b a
          -> (c, Blockchain k b d)
mapAccumR f z (Blockchain xs) = (fst res1, Blockchain res2)
  where (res1, res2) = TS.mapAccumR g (z, Nothing) xs
        g (x, prevHashMaybe) (y, oldHash) =
          let prevHash = maybe oldHash id prevHashMaybe
              (acc, val) = f x y
              hashed = hash (Proxy :: Proxy k) (val, prevHash)
          in  ((acc, Just hashed), (val, prevHash))

mapAccumR' :: forall a b c d e h k.
              (Hashable (a, b) b h, Hashable (d, e) e k)
           => (c -> a -> (c, d)) -> c -> Blockchain h b a -> e
           -> (c, Blockchain k e d)
mapAccumR' f z (Blockchain xs) initHash = (fst res1, Blockchain res2)
  where (res1, res2) = TS.mapAccumR g (z, initHash) xs
        g (x, prevHash) (y, _) =
          let (acc, val) = f x y
              hashed = hash (Proxy :: Proxy k) (val, prevHash)
          in  ((acc, hashed), (val, prevHash))

renovate :: Hashable (a, b) b h
         => Blockchain h b a -> Int -> a -> Blockchain h b a
renovate bc n y = snd $ mapAccumR f (FD.length bc - 1) bc
  where f m x = (m - 1, if m == n then y else x)

補助関数 mapAccumR は,ブロックチェーンリストを右から走査し,関数を適用しながらブロックチェーンを再構築する.f :: c -> a -> (c, d) において c はアキュムレータ,a はリストの(ハッシュを除く)要素,d はリストの(ハッシュを除く)新しい要素である.また mapAccumR' は最初のハッシュ値を新しく指定できる別種である.

例えば,次のようにすると test3 の各文字列の末尾に 100 から始まるインデックスをつけることができる.

> snd $ mapAccumR (\acc s -> (succ acc, s ++ show acc)) 100 test3
Blockchain (("3rd-block102","101kcolb-dn2001kcolb-siseneg")
  :| [("2nd-block101","001kcolb-siseneg"),("genesis-block100","")])

renovate は,ブロックチェーンリストの先頭 (0) から数えて n 番目の要素を変更する.即ち,0 番目から n - 1 番目までの要素の持つハッシュ値は全て変更される.

> renovate test3 1 "MAKE AMERICA GREAT AGAIN"
Blockchain (("3rd-block","NIAGA TAERG ACIREMA EKAMkcolb-siseneg")
  :| [("MAKE AMERICA GREAT AGAIN","kcolb-siseneg"),("genesis-block","")])

プログラム全体

他に幾つかの関数などを追加し,モジュールとメインプログラムに分割した.

  • Blockchain.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Blockchain(
  Hashable(..),
  Blockchain,
  BC,
  genesis,
  bcons,
  mapAccumR,
  mapAccumR',
  bcmap,
  renovate,
  modify,
  check,
  toList,
  toList',
  toNonEmpty,
  toNonEmpty',
  fromNonEmpty
  ) where

import Data.Foldable (foldrM)
import qualified Data.Foldable as FD
import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.List.NonEmpty as NE
import Data.Maybe (isJust)
import Data.Proxy (Proxy(..))
import qualified Data.Traversable as TS

class Hashable a b h | h -> a, h -> b where
  hash :: Proxy h -> a -> b

newtype Blockchain h b a = Blockchain (NonEmpty (a, b))
  deriving (Eq, Ord, Read, Show)

instance Foldable (Blockchain h b) where
  foldr f z (Blockchain xs) = foldr (f. fst) z xs

type BC hc b a = Blockchain (hc (a, b) b) b a

genesis :: Hashable (a, b) b h => a -> b -> Blockchain h b a
genesis x y = Blockchain $ (x, y) :| []

bcons :: forall a b h. Hashable (a, b) b h
      => a -> Blockchain h b a -> Blockchain h b a
bcons x (Blockchain xs) = Blockchain $ (x, hashed) <| xs
  where hashed = hash (Proxy :: Proxy h) (NE.head xs)

mapAccumR :: forall a b c d h k. (Hashable (a, b) b h, Hashable (d, b) b k)
          => (c -> a -> (c, d)) -> c -> Blockchain h b a
          -> (c, Blockchain k b d)
mapAccumR f z (Blockchain xs) = (fst res1, Blockchain res2)
  where (res1, res2) = TS.mapAccumR g (z, Nothing) xs
        g (x, prevHashMaybe) (y, oldHash) =
          let prevHash = maybe oldHash id prevHashMaybe
              (acc, val) = f x y
              hashed = hash (Proxy :: Proxy k) (val, prevHash)
          in  ((acc, Just hashed), (val, prevHash))

mapAccumR' :: forall a b c d e h k.
              (Hashable (a, b) b h, Hashable (d, e) e k)
           => (c -> a -> (c, d)) -> c -> Blockchain h b a -> e
           -> (c, Blockchain k e d)
mapAccumR' f z (Blockchain xs) initHash = (fst res1, Blockchain res2)
  where (res1, res2) = TS.mapAccumR g (z, initHash) xs
        g (x, prevHash) (y, _) =
          let (acc, val) = f x y
              hashed = hash (Proxy :: Proxy k) (val, prevHash)
          in  ((acc, hashed), (val, prevHash))

bcmap :: (Hashable (a, b) b h, Hashable (d, b) b k)
      => (a -> d) -> Blockchain h b a -> Blockchain k b d
bcmap f = snd . mapAccumR (\_ x -> ((), f x)) ()

modify :: Hashable (a, b) b h
       => Blockchain h b a -> Int -> (a -> a) -> Blockchain h b a
modify bc n f = snd $ mapAccumR g (FD.length bc - 1) bc
  where g m x = (m - 1, if m == n then f x else x)

renovate :: Hashable (a, b) b h
         => Blockchain h b a -> Int -> a -> Blockchain h b a
renovate bc n = modify bc n . const

check :: forall a b h. (Hashable (a, b) b h, Eq b)
      => Blockchain h b a -> b -> Bool
check (Blockchain xs) initHash = isJust $ foldrM checkf initHash xs
    where checkf (x, y) prevHash
            | prevHash == y = Just $ hash (Proxy :: Proxy h) (x, y)
            | otherwise     = Nothing

toList :: Blockchain h b a -> [a]
toList = FD.toList

toList' :: Blockchain h b a -> [(a, b)]
toList' (Blockchain xs) = NE.toList xs

toNonEmpty :: Blockchain h b a -> NonEmpty a
toNonEmpty (Blockchain xs) = NE.map fst xs

toNonEmpty' :: Blockchain h b a -> NonEmpty (a, b)
toNonEmpty' (Blockchain xs) = xs

fromNonEmpty :: forall a b h. Hashable (a, b) b h
             => NonEmpty a -> b -> Blockchain h b a
fromNonEmpty xs initHash = Blockchain $ snd $ TS.mapAccumR f initHash xs
  where f prevHash x =
          (hash (Proxy :: Proxy h) (x, prevHash), (x, prevHash))
  • Main.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Main where

import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8

import qualified Blockchain as BC

main :: IO ()
main = return ()

data MyHash a b

instance BC.Hashable (String, ByteString) ByteString
    (MyHash (String, ByteString) ByteString) where
  hash _ (s, bs) = (BL8.pack $ reverse s) `BL.append` bs

instance BC.Hashable (Int, ByteString) ByteString
    (MyHash (Int, ByteString) ByteString) where
  hash _ (x, bs) = (BL8.pack $ reverse (show x)) `BL.append` bs

test1 :: BC.BC MyHash ByteString String
test1 = BC.genesis "genesis-block" BL.empty

test2 :: BC.BC MyHash ByteString String
test2 = BC.bcons "2nd-block" test1

test3 :: BC.BC MyHash ByteString String
test3 = BC.bcons "3rd-block" test2

test4 :: BC.BC MyHash ByteString Int
test4 = BC.bcmap length test3

演習問題

  1. SHA パッケージ等を用いて SHA-256 等でハッシュするようにせよ.

  2. data BCData = BCData { content :: ByteString, nonce:: Int } 等のようなデータ型を用いるブロックチェーンを作成し,新しいブロックを作成する際に適当な条件を満たす nonce を求めるようにせよ.例えば,ハッシュした結果の先頭 n ビットが 0 であるような nonce を求めるようにする. この仕組みは PoW (Proof of Work) と呼ばれる.


  1. 途中まで String -> ByteString でいいと思っていたがこれだとリストが容易に改竄されてしまうことに気づいた

netwire であそんだ (haskell)

ちょっと前に FRP (Functional Reactive Programming) というのをよく聞いたが,使えなかったから流行らなかったのか難しいから流行らなかったのか実は流行っているのかよくわからない.

そもそも FRP 自体がよくわからなかったので netwire とかいう HaskellFRP ライブラリーを見てみたがよくわからなかった.

インターネットで検索したら netwire + GLFW で簡単なプログラムを書いている例を発見した.

bitterharvest.hatenablog.com

が GLFW が古い?(2 系?)っぽかったので GLFW-b (3系?)で書きなおしてみた.

{-# LANGUAGE Arrows #-}
module Main where

import qualified Graphics.Rendering.OpenGL.GL as GL
import qualified Graphics.UI.GLFW as GF

import Control.Wire.Core (Wire, mkGen_, stepWire, mkPure)
import Control.Wire.Session (Session, HasTime
                            , stepSession, clockSession_, dtime)
import FRP.Netwire.Move (integral, integralWith)

import Control.Applicative ((<|>))
import Control.Arrow (returnA)
import Control.Category ((>>>), (<<<))
import Control.Monad (when, unless)
import System.Exit (exitFailure)
import System.IO (hPutStrLn, stderr)

errorCallback :: GF.ErrorCallback
errorCallback err description = hPutStrLn stderr $ show err ++ description

main :: IO ()
main = do
  isInitSuccess <- GF.init
  if isInitSuccess
     then mainproc
     else exitFailure

mainproc :: IO ()
mainproc = do
  mw <- GF.createWindow 640 480 "netwire test" Nothing Nothing
  case mw of
    Nothing -> GF.terminate >> exitFailure
    Just window -> do
      GF.makeContextCurrent mw
      mainloop window
      GF.destroyWindow window
      GF.terminate

mainloop :: GF.Window -> IO ()
mainloop w = runNetwork w clockSession_ $ bouncing w

runNetwork :: Monoid a
           => GF.Window -> Session IO s -> Wire s e IO a Double -> IO ()
runNetwork w ses wire = GF.windowShouldClose w >>= \b -> unless b $ do
  GL.clear [GL.ColorBuffer]
  (nextSes, nextWire) <- stepNetwork ses wire
  GF.swapBuffers w
  GF.pollEvents
  runNetwork w nextSes nextWire

stepNetwork :: Monoid a
            => Session IO s -> Wire s e IO a Double
            -> IO (Session IO s, Wire s e IO a Double)
stepNetwork ses wire = do
  (dt, nextSes) <- stepSession ses
  (out, nextWire) <- stepWire wire dt $ Right mempty
  case out of
    Left  _ -> return ()
    Right x -> do
      GL.renderPrimitive GL.Quads $
        mapM_ renderPoint $ generatePoints x 0 0.05
  return (nextSes, nextWire)

isKeyDown :: (Monoid e, Monoid b) => GF.Window -> GF.Key -> Wire s e IO a b
isKeyDown window k = mkGen_ $ \_ -> do
  input <- GF.getKey window k
  return $ case input of
    GF.KeyState'Pressed  -> Right mempty
    GF.KeyState'Released -> Left mempty

-- isKeyDown without output (onlyl tell inhibition)
isKeyDown' :: Monoid e => GF.Window -> GF.Key -> Wire s e IO a ()
isKeyDown' = isKeyDown

-- N.B. Need Bracket (), or it may work improperly although can be compiled
acceleration :: Monoid e => GF.Window -> Wire s e IO a Double
acceleration w =
  (isKeyDown' w GF.Key'D >>> isKeyDown' w GF.Key'A >>> pure 0)
    <|> (isKeyDown' w GF.Key'A >>> pure (-0.5))
    <|> (isKeyDown' w GF.Key'D >>> pure 0.5)
    <|> (pure 0)

velocity :: (Monad m, HasTime t s, Monoid e)
         => Wire s e m (Double, Bool) Double
velocity = integralWith bounce 0
  where bounce c v
          | c         = - v
          | otherwise = v

-- pos :: HasTime t s => GF.Window -> Wire s () IO () Double
-- pos w = integral 0 <<< acceleration w

renderPoint :: (Double, Double) -> IO ()
renderPoint (x, y) = GL.vertex $
  GL.Vertex2 (realToFrac x :: GL.GLfloat) (realToFrac y :: GL.GLfloat)

generatePoints :: Double -> Double -> Double -> [(Double, Double)]
generatePoints x y s =
  [(x - s, y - s), (x + s, y - s), (x + s, y + s), (x - s, y + s)]

integralWith' :: (Fractional a, HasTime t s)
              => (a -> (a, b)) -> a -> Wire s e m a (a, b)
integralWith' correct = loop
  where loop x' = mkPure $ \ds dx ->
          let dt = realToFrac (dtime ds)
              (x, b) = correct (x' + dt * dx)
          in  x' `seq` (Right (x', b), loop x)

maxLSide :: Double
maxLSide = -0.8

maxRSide :: Double
maxRSide = 0.8

position :: (Monad m, HasTime t s) => Wire s e m Double (Double, Bool)
position = integralWith' clamp 0

clamp :: Double -> (Double, Bool)
clamp p
  | p < maxLSide = (maxLSide * 2 - p, True)
  | p > maxRSide = (maxRSide * 2 - p, True)
  | otherwise    = (p, False)

bouncing :: HasTime t s => GF.Window -> Wire s () IO () Double
bouncing w = proc _ -> do
  rec a <- acceleration w -< ()
      v <- velocity -< (a, c)
      (p, c) <- position -< v
  returnA -< p
build-depends: base
             , netwire >= 5
             , OpenGL >= 3.0
             , GLFW-b >= 0.5.2.5

目新しいのは Wire とか Arrow 記法及び Category の合成 >>> とかだと思われる.

Wire s e m a b は何かというとこんなかんじ

f:id:CyLomw:20170414204239p:plain

つまり a が入力,b が出力である関数のようなものなので,モナドではないがアローになる.加えて新しい Wire を返すが,これはどこかで見たことがあるかも知れない.

ずばりこれだろう.

data Auto a b = Auto (a -> (b, Auto a b))

これについてはここらへんをみると幸せになれる.

blog.jle.im

WireLeft が入力されるとそのワイヤーは抑制されてただ Left を返す.e はその抑制値の型.s はセッションで時間とかの入力.m はふつうモナドで,モナドの中であれこれしたいときに使う.

Wire はアローなので wire1 >>> wire2 みたいに合成できる.これはつまり wire1 の出力が wire2 の入力になる.新しいワイヤーは newwire1 >>> newwire2 となる.

f:id:CyLomw:20170414205339p:plain

<|>Alternative の合成である.これは左が Right だとそれを,左が Left だと右を返す.

例えば (isKeyDown' w GF.Key'D >>> pure 0.5) <|> (pure 0) は,D キーが押されていれば (isKeyDown'Right () を返すので,isKeyDown' w GF.Key'D >>> pure 0.5 の出力が Right 0.5 となり) 0.5 を,押されていなければ (isKeyDown'Left mempty を返すので,isKeyDown' w GF.Key'D >>> pure 0.5 の出力が Left mempty となり) 0 を出力とする.

また Wire を平行に(?)合成したい時は liftA2 とか <$>...<*> の Applicative のやつが使える.liftA2 (+) wire1 wire2 とかやると wire1wire2 にそれぞれ入力値をいれてその出力を足したやつが出力になるみたいな.

なんかもっと丁寧に書こうと思ったけどやるきなくなってしまった(おしまい)

古典ギリシア語初歩メモ(32 課 〜 36 課)

このメモは練習問題の正答ではないので,必ず↓の記事を先に読むこと.

cylomw.hatenablog.com

32 課

32-1. 我々は休戦によって解放された.

λελύμεθα (mp.perf.pl.1.) ← λύω(マクロン省略).

32-2. 敵たちはすでに征服されていた.

ἐνενίκητο(マクロン省略)(mp.plup.sg.3.) ← νῑκάω.

32-3. 戦いは終わったと彼は言う.

πέπαυται (mp.perf.sg.3.) ← παύω.

32-4. もはや熟慮する時ではない,熟慮し終える時である.今夜のうちに全てのことがなされねばならぬ.

βουλεύεσθαι (mp.inf.), βεβουλεῦσθαι (mp.perf.inf.) ← βουλεύω.ἐπιούσης (part.f.sg.gen.) ← ἔπειμι (ἐπί + εἶμι).πεπρᾶχθαι (mp.part.inf.; χσθαι → σ 消失 (§172.4)) ← πέπρᾱχα(2perf; πέπρᾱγα の別形; πέπραχ-) ← πράττω(マクロン省略)(πρᾱγ-).

32-5. アテーナイ人トゥーキューディデースは,(戦争が)おこった時,大きい戦争(になるだろうこと)を,そして以前に起きた戦争の中で最も記録に値するものになるだろうということを予期して,ただちに(記述することを)始めたことによって,ペロポンネーソス人とアテーナイ人の戦争を,互いに戦争をしたということを記述した.

ξυνέγραψε (1aor.sg.3.) ← ξυγγράφω = συγγράφω (συν-γράφω; γ の前で ν が γ に変化).ἀρξάμενος (mid.1aor.part.m.sg.nom.) ← ἄρχω.καθισταμένου (mp.part.m.sg.gen.) ← καθίστημι.ἐλπίσᾱς (1aor.part.m.sg.nom.) ← ἐλπίζω.ἔσεσθαι (fut.inf.) ← εἰμί.ἀξιολογώτατον → §68.προγεγενημένων ((mp.)perf.part.m.pl.gen.) ← προγίγνομαι.

καθισταμένου は後ろに τοῦ πολέμου を補うと,属格を用いた独立的用法の分詞 (§108.1) とわかる.中・受動相はここでは単に「(戦争が)おこった時」と訳した.

32-6-1. ソークラテースは,アルキビアデースが富の上に(の故に)正気を失っており(理性を曇らせており),潤沢(な貯え)の上に(の故に),とりわけ彼の(多くの)畑の上に(の故に)思い上がっているのを見て,世界地図が書いてある書字板が懸かっている,ポリスのとある場所の中へ彼を連れて行き,そしてアルキビアデースにその場所でアッティカ地方を探しだすことを命じた.

ὁρῶν (part.m.sg.nom.) ← ὁράω.τετῡφωμένον (mp.perf.part.m.sg.acc.) ← τῡφόω(煙に包む,[受完]正気を失っている).φρονοῦντα (part.m.sg.acc.) ← φρονέω; μέγα を伴って「思い上がる」.πλέον は πολύς の比較級.分詞を用いた間接話法 (§110.3).

ἤγαγεν (2aor.sg.3.) ← ἄγω.ἀνέκειτο ((mp.)impf.sg.3.) ← ἀνάκειμαι.ἔχον (part.n.sg.nom.) ← ἔχω;これは限定詞としての分詞 (§100) と考えた:「世界地図を持っている書字版」→「世界地図が書いてある書字版」.ἔνθα は関係副詞としても用いられるようなので,ここではそう考えて訳した.

32-6-2. 彼(アルキビアデース)が発見した時,彼(ソークラテース)は彼(アルキビアデース)に自分の畑をくわしく調べる(探す)よう命じた.

εὗρε (2aor.sg.3.) ← εὑρίσκω.

32-6-3. すると彼(アルキビアデース)は言った,「しかし,(畑が)書かれているところはどこにもない,」彼(ソークラテース)は言った,「さて,その上に(その故に)(君は思い上がっているのか?),」「君は大地の何の部分でもないところの上に(の故に)思い上がっているのか?」

εἰπόντος (2aor.part.m.sg.gen.) ← εἶπον (2aor.).これは属格を用いた独立的用法の分詞 (§108.1) と考えられる;即ち主文の動詞 εἶπε (2aor.sg.3.) の主語(ソークラテース)と異なる人(アルキビアデース)が分詞 εἰπόντος の主語となっている.τοῦ δὲ は,主語(ここでは分詞 εἰπόντος の主語アルキビアデース)が前文のそれ(ソークラテース)とは変わったことを示す (練習 14.10 の注を参照).

γεγραμμένοι (mp.perf.part.m.pl.nom.) ← γέγραμμαι (mp.perf.sg.1.; φ + μ → μμ: §172.1) ← γράφω.οἵπερ は関係代名詞 οἵ に強調の前接辞 πέρ がついた合成語.οὐδεν は形容詞的に用いられることがあるので,そう考えて訳した.

33 課

33-1. (君は)ゆっくり急げ.

33-2. (君たちは)裁いてはいけない,(君たちが)裁かれないために.

κριθῆτε (pass.subj.1aor.pl.2.) ← κρίνω(マクロン省略);κρίθητε (pass.imp.1aor.pl.2) と間違わないよう注意.

κρίνω(マクロン省略;ι は長母音)の動詞幹は κρι-(ι は短母音)であるが,現在・未来およびアオリスト能動相と中動相においては ν が付加され流音幹となる.また現在 (流音・鼻音幹動詞でしばしばこの長音化が起こる: Ciesko 7§45) 及びアオリスト (ἔκρῑνα: §38.3) では ι が長音となる.

33-3. (君は)ただ顔だけを洗うな,罪を洗え.

33-4. 「ごきげんよう,友よ,」彼は言った,「(君は)私にこまめに(手紙を)書け.」

33-5-1. ソローンは次のことを人々に忠告した:誓いよりも,信頼すべき人柄の立派さを持て.

συνεβούλευσε (1aor.sg.3.) ← συμβουλεύω (συν-βουλεύω; ν が β の前で μ に変化).比較の属格 (§73.2).

33-5-2,3. 嘘をついてはいけない.まじめさを実行せよ.

ψεύδου (mp.imp.sg.2.) ← ψεύδω.μελέτᾱ (imp.sg.2.; μελέτα-ε) ← μελετάω.

33-5-4. 速く友人たちを得(ようとし)てはいけない:もし(友人を)得たなら,彼らを不適当として退けてはいけない.

κτῶ ((mp.)imp.sg.2.), κτήσῃ ((mid.)subj.1aor.sg.2.) ← κτάομαι.関係代名詞と ἄν による実現可能な未来の仮定 (§116.1, §117);関係代名詞 + ἄν の構文では関係代名詞がしばしば不定関係代名詞のように扱われる.

33-5-5,6. まず支配されることを学んだ後に支配せよ.最も楽しいこと(喜ばせること)ではなく(その人にとって)最良のことを(人に)忠告せよ.

μαθὼν (2aor.part.m.sg.nom.) ← μανθάνω.

33-5-7,8,9. 理性を案内人とせよ.悪い者たちと交際してはいけない.神を尊重し,親を敬え.

ποιοῦ (mp.imp.sg.2.) ← ποιέω.ποιέω:[対格]を[対格]にする;ここでは中動相で「自分のために」「自分で」(強意の中動)などの意味であると思われるが,よくわからない.αἰδοῦ ((mp.)imp.sg.2.; αἰδέ-ου) ← αἰδέομαι.

33-6-1. 「もし他のある人がよりよいものを見るならば(よりよい意見があれば),(その人はそれを)言え.」

33-6-2. 誰も反対していなかったので,彼(クセノポーン)は言った,「(自分にとって)それらを良いと思われたものは誰でも,手を挙げよ.」彼はそれらを決議した.

ἀνατεινάτω (imp.1aor.sg.3.) ← ἀνατείνω.

33-6-3. 「さて,それでは,」彼は言った,「(我々は)立ち去って,決議された事々をせねばならぬ.

ἀπιόντας (part.m.pl.acc.) ← ἄπειμι.δεδογμένα (mp.perf.part.n.pl.acc.) ← δοκέω.

33-6-4. そして君たちの家の者たちを見ることを切望する者は誰でも,(自分が)立派な男であることを憶えておけ:というのも,他の方法でこれ(この望み)を手に入れることはできないからである:生きることを切望する者は誰でも,勝つ努力をせよ.」

ἰδεῖν (2aor.inf.) ← εἶδον (2aor.) ← ὀράω.μεμνήσθω (mp.imp.perf.sg.3.) ← μιμνῄσκω.τυχεῖν (2aor.inf.) ← ἔτυχον (2aor.) ← τυγχάνω.πειράσθω ((mp.)imp.sg.3.;マクロン省略;πειρα-έσθω) ← πειράομαι.

34 課

34-1. 私に,私がどこで立ったらいいか与えよ,そして私は大地を動かすだろう(動かそう).

στῶ (subj.2aor.sg.1.) ← ἵστημι;思案・熟慮の接続法と考えた.κῑνήσω は fut.sg.1. か subj.1aor.sg.1. だがどちらであるかよくわからない.接続法であれば提案の接続法として訳せるだろう.

「私に支点を与えよ,そうすれば地球を動かしてみせよう」などとして知られるアルキメデスの言葉.

34-2. カイサルのものをカイサルに,神のものを神に返せ.

ἀπόδοτε (imp.2aor.pl.2.) ← ἀποδίδωμι.

34-3. おおギリシア人たちの子どもたちよ,行け,祖国を解放せよ,こどもたちを,女たちを,父祖伝来の神々の社を,祖先の墓を,解放せよ:いま戦いは全てのために.

ἴτε (imp.pl.2.) ← εἶμι.ἐλευθεροῦτε (imp.pl.2.) ← ἐλευθερόω.γυνή の変化は練習 9 の単語リストを参照.

34-4-1. 与えられた線分を2つに切る事.

δοθεῖσν (pass.1aor.part.f.sg.acc.) ← δίδωμι.πεπερασμένην (mp.perf.part.f.sg.acc.; §174.1) ← περαίνω (語幹 περαν-).τεμεῖν (2aor.inf.) ← ἔτεμον (2aor.) ← τέμνω.

「限られた(注参照)直線」とは,長さが有限の直線,即ち線分のこと.注にある γραμμήν (f.sg.acc.) ← γραμμή は線,ライン.

34-4-2. ΑΒ は与えられた線分であるとせよ:今,線分 ΑΒ を2つに切らねばならぬ.

ἔστω (imp.sg.3.) ← εἰμί.

34-4-3. それ(線分)の上に等辺三角形 ΑΒΓ が結びついているとせよ,そして ΑΓΒ によってつくられた角は ΓΔ によって2つに切られたとせよ:私は線分 ΑΒ が点 Δ において2つに切られたということを(今から)言う(示す).

συνεστάτω (imp.2perf.sg.3.) ← συνίστημι,この動詞の変化は巻末 D.9 (ἵστημι) を参照;ἵστημι の完了 ἕστηκα は「立っている」と自動詞・現在の意味で用いられ (§165.2) ,συνίστημι においても同様なので「結びついているとせよ」と訳した.τετμήσθω (mp.imp.perf.sg.3.), τέτμηται (mp.perf.sg.3.) ← τέτμηκα (1perf.) ← τέμνω (τεμ-, 完了では τμη-).

34-4-4. ΑΓ は ΓΒ に等しく,ΓΔ は共通であるから,確かに (ΑΓ,ΓΔ) の2つは,(ΒΓ,ΓΔ) の2つに,各々が各々に等しい.

34-4-5. そして ΑΓΔ によってつくられた角は ΒΓΔ によって作られた角に等しい:ゆえに底辺 ΑΔ は底辺 ΒΔ に等しい.

34-4-6. ゆえに与えられた線分 ΑΒ は Δ において2つに切られている:これがまさにせねばならなかったことである.

ὅπερ は関係代名詞 ὅ に強調の前接辞 πέρ がついた合成語.先行詞が省略されて,「(まさに)せねば(作らねば)ならなかったこと」.類語に ὅπερ ἔδει δεῖξαι (Ο.Ε.Δ.) (羅 quod erat demonstrandum: Q.E.D.)「(まさに)示さねばならなかったこと」がある.

35 課

35-1. 汝自身を知れ.

35-2. 愚かな者は経験することによって(はじめて)知るのだ.

παθὼν (2aor.part.m.sg.nom.) ← ἔπαθον (2aor.) ← πάσχω.ἔγνω は格言のアオリストと考えられる (練習 7.9 の注を参照).

35-3. 私は昨日アリストーンの息子グラウコーンとともにペイライエウスへ下った.

35-4. 私はアーゲーシラーオスの徳と名声の価値がある称賛(彼には徳と名声があると言うに値するのだという称賛?)を書くことは容易でないということを知っているが,それでもやはり試みるべきである.

35-5-1. 私は,ちょうど他のギリシア人たち(がそう言っているの)と同じように,アテーナイ人たちは賢いと言っている.

φημί 対格 + 不定詞

35-5-2. さて私は,ポリスが建築についてのことを行わねばならぬために,我々が,建造物について建築家たちを,造船について船大工たちを,また他の全ての事々についてもこのように助言者たちを呼び寄せて,民会の中へ集める時はいつでも,彼らが学び得る,教えられ得ることがあると考えるほど多くのことを見る.

接続法は現在の一般的な仮定 (§116.2, §117, ὅταν = ὅτε ἄν, ἐπειδάν = ἐπεί ἄν).δέῃ (subj.) ← δεῖ.πρᾶξαι (1aor.inf.) ← πράττω(マクロン省略)(πρᾱγ-).

ここの訳にはあまり自信がない.

35-5-3. そしてポリスの管理の事々について熟慮せねばならぬ時,彼は,また同様に大工は,鍛冶屋は,靴屋は,商人は,船長は,金持ちの人は,貧乏人は,高貴な人は,卑賤な人は,立ち上がって彼らにそれらのことについて忠告する;彼(忠告した人)はどこからも学んでいない,また彼には誰か先生がいるわけでもないと彼らに非難する人は誰もいないし,それから彼(忠告した人)に忠告する(忠告し返す)ことを試みようとする人もいない:というのも,(こういうことは)教えられ得るものではない(誰かに教えてもらえるようなことではない)と彼らが考えていることは明らかであるからである.

μαθών (2aor.part.m.sg.nom.) ← μανθάνω.ὄντος (part.m.sg.gen.) ← εἰμί;属格を用いた独立的用法の分詞 (§108.1).τοῦτο は ὅτι 以下のことを指していると考えられる. ὅτι 節には分詞のみがあり動詞が存在しないが,分詞が名詞扱いされ「どこからも学んでいない者」,(οὐδενός を形容詞的に考えて)「先生のいない者」として έστί が省略されている(彼はどこからも学んでいない者だ,先生のいない者だ)という形なのかもしれない.

最初の περὶ τῶν τῆς πόλεως διοικήσεως の τῶν はよくわからなかったので「事々」(の複数属格:περὶ は属格または対格支配)が省略されていると考えた.また ἐπιπλήττω は与格を(も?)とる.

36 課

36-1. 牝ライオンは,いつでも1匹(の子)を産むこと(1匹しか子を産まないこと)について狐に非難され,言った,「1匹だ(1匹をしか産まないが),」「しかし,ライオン(を産むの)だ.」

ἐπί は「〜について」くらいの意味だろう.

36-2. 軍隊がアウリス港に集められていた.全部で 1013 隻の船があり,43 人の指導者がいた.

νῆες (f.pl.nom.) ← ναῦς (§63).

36-3. 私カリクラテイアは 29 人の子どもを産んだが,私は一人の男の子の死をすら,そして一人の女の子の死をすらも見なかった:しかし 105 年間,震える手を杖に置くことなく,私は人生を終えた.

τεκοῦσα (2aor.part.f.sg.nom.) ← τίκτω.ἐδρακόμην ((mid.)2aor.sg.1.) ← δέρκομαι.διηνυσάμην (mid.1aor.sg.1.) ← διανύω.ἐπιθεῖσα (2aor.part.f.sg.nom.; §105) ← ἐπιτίθημι.

期間の対格 (§46.1).中動相の διηνυσάμην は「自分を終える」から「自分の人生を終える(た)」くらいの意味だろう.

36-4-1. 生じたことはそのような(次のような)ことであった.各々が陶片を手にとって市民たちのうちの立ち退かせたい人(の名)を書き,広場の1つの場所の中へ運んでいた.支配者たちは最初に陶片の全部の数を数え上げていた:書いた者たちが 6000 人より少ないと,追放は無効であった.それから名前の各々を別々にして(名前ごとにわけて),最も多くの者たちによって書かれていた人を(に対して) 10 年間の追放宣言をしていた.

ἦν (impf.sg.3.),εἶεν (opt.pl.3.) ← εἰμί.λαβὼν (2aor.part.m.sg.nom.) ← λαμβάνω.μεταστῆσαι (1aor.inf.) ← μεθίστημι (μετά-ἵστημι).θέντες (2aor.part.m.sg.nom.) ← τίθημι.γεγραμμένον (mp.perf.part.m.sg.acc.) ← γράφω.ἐξεκήρυττον (impf.pl.3.; §35) ← ἐκκηρύττω.

36-4-2. さて陶片が書かれていた当時,文盲でド田舎に住んでいた人たちのうちのある人が,たまたまそこにいた者たちのうちの1人に(そうするように),アリステイデースに陶片を渡し,(陶片に)アリステイデース(の名)を書き込むために助けを求めたと言われている.彼(アリステイデース)が驚いて,アリステイデースが彼になにか悪いことをしたのではないかと(思って)訪ねると,彼(ある人)は言った,「何をも(悪いことをしていない),」「私はその人を知ってさえいない,しかし至るところで“正しい人”のことを聞くので困っている.」それらのことを聞いてアリステイデースは何をも答えず,彼の(自分の)名前を陶片に書き込んで返した.

ἀναδόντα (2aor.part.m.sg.acc.) ← ἀναδίδωμι.τυχόντων (2aor.part.m.pl.gen.) ← τυγχάνω.ἐγγράψειε (opt.1aor.sg.3.), ἐνέγραψε (1aor.sg.3.) ← ἐγγράφω (ἐν-γράφω).πυθομένου ((mid.)2aor.part.m.sg.gen.) ← πυνθάνομαι.ἀπεκρίνατο(マクロン省略)((mid.)1aor.sg.3.) ← ἀποκρίνομαι(マクロン省略).ἀπέδωκεν (2aor.sg.3.) ← ἀποδίδωμι.

λέγεταί (mp.sg.3.) + τινα(対格)+ παρακαλεῖν (inf.):「ある人が助けを求めたと言われている」 (It is said…),漠然とした噂,話のようなものが文の主語となっていると考えられる (Ciesko 8§12).

「正しい人」(ὁ Δίκαιος) は,アリステイデースの渾名らしい.

古典ギリシア語初歩メモ(27 課 〜 31 課)

このメモは練習問題の正答ではないので,必ず↓の記事を先に読むこと.

cylomw.hatenablog.com

また,はっきり言っておくが*1,ここにメモを残すのは古典ギリシア語を学んでいる・学びたい者たちのためであって,単位が欲しいだけの学生のためではない.勝手に使う分には自由であるが.

27 課

27-1. もし君が若い妻を娶っていたら,既におじいさんになっていただろう.

ἔγημας (1aor.sg.2.) ← γαμέω((妻を)娶る;動詞幹 γαμ-).ἦσθα (impf.sg.2.) ← εἰμί.εἰμί にはアオリストがないため未完了過去を用いていると考えられる.そもそも事実に反する仮定の条件文に於いて,未完了過去とアオリストはそれぞれ単に継続的か1回的かという動作態(相,アスペクト)の相違のみを表す (Ciesko 8§53.4).現在 / 過去の事実に反する仮定とは,そのそれぞれの動作態から現れるものである.

27-2. その場にいなかった,そして自国にとどまってさえいなかった私が,いかにして(なぜ)君を害したのか(,害していない).

前文のない,事実に反する仮定の条件文と考えられる.παρὼν (part.m.sg.nom.) ← πάρειμι(その場にいる),この動詞の変化は εἰμί を参照.ἐπιδημῶν (part.m.sg.nom.) ← ἐπιδημέω(自国にとどまる).2つの分詞は否定を伴って ἐγώ を限定的に修飾していると考えた (§100).ἠδίκησα (1aor.sg.1.) ← ἀδικέω(不正を働く,[対格]を害する,傷つける,中傷する).σ' ← σέ.

27-3. 我々が君たちに笛を吹いたが,君たちは踊らなかった.我々が挽歌を歌ったが,君たちは泣かなかった.

ηὐλήσαμεν (1aor.pl.1.) ← αὐλέω(笛を吹く).ὠρχήσασθε ((mid.)1aor.pl.2.) ← ὀρχέομαι(踊る).ἐθρηνήσαμεν (1aor.pl.1.) ← θρηνέω(挽歌を歌う,嘆く).ἐκλαύσατε (1aor.pl.2.) ← κλαίω(泣く).

κλαίω の動詞幹は κλαυ- であるが,現在幹は κλαι-ε/ο- または κλᾱ-ε/ο-(古いアッティカ方言形)となる(母音融合しない).よって現在 κλαίω または κλάω(α のマクロン省略),未完了過去 ἔκλαιον または ἔκλᾱον,第一アオリスト ἔκλαυσα.

また κλαίω の未来は中動相を能動の意味で用いて κλαύσομαι であるが,アッティカ方言では κλαιήσω または κλᾱήσω という形もあった.これは,κλαύσομαι が「泣くことになるぞ」(脅し)の意味で用いられるようになったためである (Ciesko 7§58).

※ κλαίω の動詞幹は正確には κλαϝ-(ϝ はディガンマという古いギリシャ文字音価は [w])であり,このためにやや奇妙な変化となる.同様の変化をする動詞に καίω(焼く;動詞幹 καϝ-) がある (Ciesko 7§58).

27-4. というのも,今も最初も人々は驚くこと故に(によって)哲学することを始めたからである.

ἤρξαντο (mid.1aor.pl.3.) ← ἄρχω(支配する,[中]始める).

27-5. そして彼(アルタクセルクセース)が,それ(ティッサペルネースの中傷)に従い,殺すためにキューロスをとらえる(とらえた).しかし母が彼をもらい下げ,再び領地の方へ送り返す(送り返した).

24-10 と同様に歴史的現在を用いた文.ἀποκτενῶν (fut.part.m.sg.nom.) ← ἀποκτείνω(殺す),動詞幹 ἀποκτεν- より未来形に注意 (§81).ἐξαιτησαμένη (mid.1aor.part.f.sg.nom.) ← ἐξαιτέω(要求する,[中]もらい下げる).

27-6. もし神が人々の祈りに従っていれば,(人々が)ひっきりなしに互いに対して多くの困難なことを祈るために,多くの人々はより速く滅びているだろう.

θᾶττον は形容詞 ταχύς(速い)の比較級 θάττων(マクロン省略)の中性単数対格形からつくられた副詞の比較級.κατηκολούθει (impf.sg.3.) ← κατακολουθέω(従う).ἀπώλλυντο (mp.impf.pl.3.) ← ἀπόλλῡμι(ほろぼす,破壊させる,[中]ほろびる,死ぬ).εὐχόμενοι ((mp.)part.m.pl.nom.) ← εὔχομαι(祈る).

ἀπόλλῡμι は未完了過去 ἀπώλλῡν.能動相現在及び能動相未完了過去では単数形で ῡ,複数形で υ;中・受動相では単数でも複数でも υ を用いる (δείκνῡμι と同様).よって中動相未完了過去は ἀπωλλύμην.また未来 ἀπολῶ,第1アオリスト ἀπώλεσα,第1完了 ἀπολώλεκα.

27-7-1. 法は言うだろう,「おおソクラテスよ,我々(法)にとって,我々(法)とポリスが君の気に入っていたということ,その証拠は大きい.

ἠρέσκομεν (impf.pl.1.) ← ἀρέσκω([与格]の気に入る,を喜ばす).また注にあるように φαῖεν (opt.pl.3.) ← φημί,可能性の希求法 (§121.2, §124).法が喋るようなことがあればこう言うだろう,という気持ちがあるのかもしれない.

27-7-2. というのも,もしとくに君の気に入っていないのであれば,他のすべてのアテーナイ人たちと異なり,それ(ポリス)の中に君がとどまっていないだろうからである.」

ἀπάντων (m/n.pl.gen.) ← ἄπᾱς(すべての).ἤρεσκεν (impf.sg.3.) ← ἀρέσκω.ἐπεδήμεις (impf.sg.2.) ← ἐπιδημέω(自国にとどまる).現在の事実に反する仮定.ποτέ(前接辞)は「いつ (when),いつか (someday),いったい(疑問代名詞を強めて;一体全体)」であるが,無理に訳さなくていいだろう.君がいつか出て行ってしまうようなことがなく他のアテーナイ人たちと同様にポリスに留まっていたということは,君がポリスを気に入っているという証拠だ.

28 課

28-1. もし君が欲するならば,君はできるだろう.

実現可能な未来の仮定 (§116.1).βούλῃ ((mp.)subj.sg.2.) ← βούλομαι(欲する),mp.ind.sg.2. と同形なので注意.δυνήσῃ ((mid.)fut.sg.2.) ← δύναμαι(できる),mid.subj.1aor.sg.2. と同形なので注意.

28-2. そして彼らは(私は)暗くなるまでそれらを作っていた(していた).

ἐποίουν (impf.sg.1. / pl.3.) ← ποιέω(つくる,する).ἐγένετο ((mp.)impf.sg.3.) ← γίγνομαι(生じる,生まれる,……になる).

28-3. たとえ彼が幸運であるように思われても,彼が死ぬのを見るまで君は妬むな.

εὐτυχεῖν (inf.) ← εὐτυχέω(幸運である).δοκοῦντα (part.m.sg.acc.) ← δοκέω(思われる,よいと思われる,決議する),ここでは譲歩の分詞と考えた (§101.5).δοκέω 対格 + 不定詞 構文だが,対格部分(不定詞の主語)は τὸν だけで具体的に書かれてはいないため,適当に「彼」と訳した.ところで δοκέω は非人称動詞としても用いられるが,その場合分詞は中性単数対格になるはずなので (§108.2),ここでは単に「彼」が主語になっているのであろう.

注にあるように ζήλου (imp.sg.2.) ← ζηλόω(羨む,妬む).θανόντ' ← θανόντα (2aor.part.m.sg.acc.) ← ἔθανον (2aor.) ← θνῄσκω(死ぬ),この分詞の主語にあたる部分は τὸν のところなので m.sg.acc. であると考えられる.ἴδῃς (subj.2aor.sg.2.) ← εἶδον (2aor.) ← ὁράω(見る).

28-4. 富が,悪い人間や,心がふさわしくない人についていく時はいつでも,飽満は確かに傲慢を産む.

ὅταν を用いた現在の一般的な仮定 (§116.2, §117).ἕπηται ((mp.)subj.sg.3.) ← ἕπομαι(従う,ついていく).ᾖ (subj.sg.3.) ← εἰμί.

28-5-1. 生きているあいだ,そして(そのようなことが)出来るあいだは,哲学することを,そして君たちに(哲学することを)命ずる(勧める)ことを,そして常に君たちの(うちの)私がたまたま出会った人々全てに示すことを私は決して止めないだろう,

ἕωσπερ は,ἕως(……するまで,する間)に強調の前接辞 πέρ がついた合成語.οἷάπερ も同様,οἷα (n.pl.nom./acc.) ← οἷος + πέρ(前接辞).ἐμπνέω (subj.sg.1.) ← ἐμπνέω, ind.sg.1. と同形なので注意.πνέω は2音節の -έω 動詞なので,ει 以外には融合せず,合成動詞 ἐμπνέω (ἐν-πνέω) においても同様 (練習 14.6 の注を参照).ὦ (subj.sg.1.) ← εἰμί; οἷός τε εἶναι で「〜できる,能力がある」.

φιλοσοφῶν (part.m.sg.nom.), παρακελευόμενός ((mp.)part.m.sg.nom.), ἐνδεικνύμενος (mp.part.m.sg.nom.) は παύσωμαι (mid.subj.1aor.sg.1.) の補語 (§110.1).注にあるように,οὐ μή + 接続法アオリストで未来の強い否定を表している.また ἐνδεικνύμενος は中動相だが,「示す」でよいようだ.

ἕωσπερ ≒ ἕως を用いて,反復されることがらを表す文 (§149.2) .主文が本時称(接続法や命令法は常に本時称と見做される: Ciesko 8§67)なので,従属文は接続法と ἄν をとっている.

28-5-2. 「おお,ポリスの(中で),知と力において最大のそして最も評判のいい男たちの中で最良のアテーナイ人よ,一方君は金銭や名声や名誉が君にとってできるだけ最も多くなるように気をつけていることを恥じないが,他方君は思慮分別や真実や魂ができるだけ最もよくなるように気をつけたり,熟慮したりしない.」という,私がいつも言っているようなことを言うことによって(示すことを私は決して止めないだろう).

注にあるように,εἴωθα (2perf.sg.1.) ← ἔθω(……する習慣がある).完了は,ある動作が完了して,その結果が現在に及んでいることを示す時称 (§159) であり,「〜し終えている」「(なんらかの動作の結果)〜している」と訳す.ここでは注にあるように λέγειν (inf.) を補って,「言うことが習慣になっている」→「いつも言っている」と訳した.

ὤν (part.m.sg.voc.) (← εἰμί) は名詞扱いされた分詞と考え,「(〜男たちの中で)最良のアテーナイ人であるものよ」→「最良のアテーナイ人よ」と訳した.

αἰσχύνῃ(マクロン省略)(mp.sg.2.) ← αἰσχύνω(マクロン省略)(恥をかかせる,[中]恥じる([分詞]しているのを恥じる,[不定詞]することを恥じる: Ciesko 8§28.1)).ἐπιμελῇ ((mp.)sg.2.) ← ἐπιμελέομαι(気をつける,注意する).ὅπως + 直説法未来 は,配慮や努力を表す文 (§144).

χρημάτων, δόξης, τῑμῆς, φρονήσεως, ἀληθείᾱς, ψῡχῆς は全て属格となっているが,これはこれらが(主語になっているのではなく)ἐπιμελούμενος ((mp.)part.m.sg.nom.) 及び ἐπιμελῇ の目的語になっているためと考えられる;ἐπιμελέομαι は対格や不定詞の他に属格もとるらしい (to take care of).「できるだけ金銭や名声や名誉が最も多くなるように(最も多くの金銭や名声や名誉が存在するように),金銭や名声や名誉の世話をすることを恥じない」かな? 実際よくわからない.俺たちは雰囲気で属格をやっている.

29 課

29-1. 私はあなたの言葉に従わないだろう.

πιθοίμην (mid.opt.2aor.sg.1.) ← πείθω(説得する;[中・受](与格と)……に従う).σοῖς (m.pl.dat.) ← σός(あなたの)(§143).

29-2. 君は星々を眺めている,私のアステール.多くの目で君を眺めるために私が天になれればよいのだが.

γενοίμην ((mp.)opt.2aor.sg.1.) ← ἐγενόμην ((mp.)2aor.) ← γίγνομαι(生じる,生まれる,……になる).願望・可能性の希求法 (§121) は常に本時称と見做される (Ciesko 8§67) ので,ὡς 以降の目的表現の従属文は接続法になるはずである (§123).即ち βλέπω は subj.sg.1. であると考えられる.βλέπω εἰς ...(……を見る,眺める).

29-3. その時キューロスには王宮と,野生の野獣に満ちた大きい猟園があった.彼は,彼自身と彼の馬が訓練することを欲する時はいつでも,馬からそれらを狩っていた.

ἦν (impf.sg.3.) ← εἰμί.γυμνάσαι (1aor.inf.) ← γυμνάζω(鍛える,訓練する).βούλοιτο ((mp.)opt.sg.3.) ← βούλομαι(欲する),過去の一般的な仮定 (§124.2, §125).ἃ (n.pl.nom./acc.) は関係代名詞;ここでは θηρίων を指していると考えた.

29-4. 増大したペルシア人たちの国事が,(一方)クロイソスの悲嘆を止め(クロイソスを悲嘆から離れさせ),(他方)(以下の)考えの中に立ち至らせた.なんとかして,(力の)大きいペルシア人が生じる前に,彼の力の増大を抑止することができればなあ(という考えに至らせた).

ἀπέπαυσε (1aor.sg.3.) ← ἀποπαύω([属格]を止めさせる).ἐνέβησε (1aor.sg.3.) ← ἐμβαίνω (ἐν-βαίνω).δύναιτο ((mp.)opt.sg.3.) ← δύναμαι(できる).γενέσθαι ((mp.)2aor.inf.) ← ἐγενόμην ((mp.)2aor.) ← γίγνομαι(生じる,生まれる,……になる).καταλαβεῖν (2aor.inf.) ← καταλαμβάνω(とらえる,抑止する).

29-5.

ソークラテース:悪いことの(中で)最大のことは,(たまたま,)不正を働くことである.

ポーロス:本当にそれが最大なのか? 不正を受けることがより大きいのではないのか?

ソ:少なくともそうでは決してない.

ポ:すると君は不正を働くことよりもむしろ不正を受けることを欲するのだろうか?

ソ:私はそのいずれも欲しないだろう.しかし,もし不正を受けることか不正を働くことが避けられないのであれば,私は不正を働くよりもむしろ不正を受けることをとるだろう.

ὂν (part.n.sg.nom.) ← εἰμί.τυγχάνω ὤν ... : たまたま……である;「意外にも」としてもいいのかもしれない.ἦ γάρ: 本当に……か.ἔγωγε は ἐγώ の強調形.εἴη (opt.sg.3.) ← εἰμί.ἑλοίμην (mp.opt.sg.1.) ← εἷλον (2aor.) ← αἱρέω(取る,つかまえる).

30 課

30-1. ソーソスとソーソーは,救済者よ,あなたにこれを奉納しました,ソーソスは救われたために,ソーソーはソーソスが救われたために.

ἀνέθηκαν = ἀνέθεσαν (2aor.pl.3.) ← ἀνατίθημι(奉献する,奉納する).σωθείς (pass.1aor.part.m.sg.nom.) ← ἐσώθην (pass.1aor.) ← σῴζω(救う).

30-2. もし私が死の影の中央に行くならば(行ったとしても),私は悪いこと(災い)を恐れないだろう,あなたが私と共にいるから.

φοβηθήσομαι (pass.1fut.sg.1.) ← φοβέω(恐れさせる,[中・受]恐れる).εἶ (sg.2.) ← εἰμί もしくは εἶμι.

30-3. キューロスは,危険をおかし侮辱され立ち去った時に,もはや決して兄の手中に落ちないよう熟慮する.しかし,もしできるなら,彼のかわりに王であるだろう.

24-10, 27-5 と同様に歴史的現在を用いている.配慮や努力の文を導く ὅπως (§144).ἢν = ἐάν(マクロン省略)(§116.1).ἀπῆλθε (2aor.sg.3.) ← ἀπέρχομαι(立ち去る).κινδῡνεύσᾱς (1aor.part.m.sg.nom.) ← κινδῡνεύω(危険をおかす).ἀτῑμασθείς (pass.1aor.part.m.sg.nom.) ← ἠτῑμάσθην (pass.1aor.) ← ἀτῑμάζω(侮辱する).δύνηται ((mp.)subj.sg.3.) ← δύναμαι(できる).

30-4. というのも,もしある人が歴史から「なにゆえに」「いかにして」「なされたことは,誰のためになされたのか」「結果(目的)が合理的であるか否か」を取り去ったならば,後に残るものは歴史の(単なる)作品であり,教訓になるものではなく,そして直ちには(人々を)喜ばせるが,未来に向かって(今後)誰をも助ける(誰かの益になる)ことはまったくないからである.

ἱστορίᾱς (f.sg.gen.) は分離の属格.χάριν は注を参照.ἀφέλῃ (subj.2aor.sg.3.) ← ἀφαιρέω(取り去る).ἐπράχθη(マクロン省略)(pass.1aor.sg.3.), πρᾱχθὲν (pass.1aor.part.n.sg.nom.) ← πράττω(マクロン省略)(行う,なす)(動詞幹 πρᾱγ-).ἔσχε (2aor.sg.3.) ← ἔχω(持つ,……の状態である).

30-5-1. オルペウスの妻,エウリュディケーが蛇に咬まれて死んだ.

δηχθεῖσα (pass.1aor.part.f.sg.nom.) ← ἐδήχθην (pass.1aor.) ← δάκνω(咬む).ἀπέθανεν (2aor.sg.3.) ← ἀποθνῄσκω(死ぬ).

30-5-2. オルペウスは冥府へ下り,彼女を送り返すようプルートーンを説得した.

κατελθὼν (2aor.part.m.sg.nom.) ← κατέρχομαι(下る,下りる).ἔπεισεν (1aor.sg.3.) ← πείθω(説得する).ἀναπέμψαι (1aor.inf.) ← ἀναπέμπω(送り返す).

30-5-3. 彼(プルートーン)は,(オルペウスが)行く(帰る)時に,もし家の中へ着く前にオルペウスが振り向かなければそれをすると約束した.

ὑπέσχετο ((mid.)2aor.sg.3.) ← ὑπισχνέομαι(約束する).ἐπιστραφῇ (pass.subj.2aor.sg.3.) ← ἐπιστρέφω(向きを変える,回す;[中・受]ふりむく).παραγενέσθαι ((mid.)2aor.inf.) ← παραγίγνομαι(そばにいる,来る,着く).πρίν + 不定詞 は §150.1 を参照;主文が肯定文ではない気がするが,よくわからん.

30-5-4. しかし彼はそれに従わずふりむいて妻を見た,そして彼女は再び冥府へ連れて行かれた.

ἀπιστῶν (part.m.sg.nom.) ← ἀπιστέω(信じない,従わない).ἐπιστραφεὶς (pass.2aor.part.m.sg.nom.) ← ἐπιστρέφω.ἐθεάσατο(マクロン省略)((mid.)1aor.sg.3.) ← θεάομαι(見る,見物する).κατηνέχθη (mid.1aor.sg.3.) ← καταφέρω(下方へ運ぶ).

31 課

31-1. 詩人たちの(うちの)ある人々が,いかに生きねばならぬかという助言を後に残している.

καταλελοίπᾱσιν (2perf.pl.3.) ← καταλείπω.このように完了幹の形成の際 ε から ο への母音交替が発生することがある(また語根末尾は帯気音化することがある;例 κλέπτω (κλεπ-) → κέκλοφα) (Ciesko 7§1.3).ζῆν (inf. この動詞は特別の母音融合を行う;練習 14 の単語リスト参照) ← ζάω.ὡς は関係副詞のように使われることがある.

31-2. そして私にとってそうなっていることは予期しないものではなかった,あなたがたが私に有罪の投票をしたから.

γέγονεν (2perf.sg.3.), γεγονὸς (2perf.part.n.sg.nom.) ← γέγονα (2perf.) ← γίγνομαι.γίγνομαι は完了・過去完了にのみ能動相が存在するがどの相でも意味はほとんど変わらない;未来とアオリストに存在する受動相も同様.τὸ γεγονὸς τοῦτο((そう)なっているそれ or その(そう)なっていること)が主語と考えられる.

31-3. ソクラテスは夜明けになり太陽が昇るまで立っていて,それから太陽に祈りを捧げ立ち去った.

ἕως は名詞「夜明け,暁」の方なので注意.εἱστήκει (1plup./2plup.sg.3.; §165 にあるように ἵστημι は単数では第1完了・第1過去完了,複数では第2完了・第2過去完了の形となる) ← εἱστήκη (1plup./2plup.; 立っていた) ← ἵστημι.ἐγένετο ((mid.)2aor.sg.3.) ← γίγνομαι.ἀνέσχεν (2aor.sg.3.) ← ἀνέχω (ἀνά-ἔχω).ᾤχετ' ← ᾤχετο ((mp.)impf.sg.3.) ← οἴχομαι.ἀπιὼν (part.m.sg.nom.) ← ἄπειμι.προσευξάμενος ((mid.)1aor.part.m.sg.nom.) ← προσεύχομαι.

31-4. 我々は神の誓いを堅持しているが,敵達は偽誓し,そして誓いに反して休戦条約を破っている.

31-5. しかし私は,我々が一度,怠慢に生きることや豊富の中で暮らしを立てること,メーディアー人やペルシア人の美しく大きい女たちや乙女たちと交際することを学んだら,(記憶を喪失させるというロートスの実を食している)ロートパゴイのように,家への道を忘れてしまうのではないかと実に恐れている.

δέδοικα (1perf.sg.1.) ← δείδω.μάθωμεν (subj.2aor.pl.1.) ← μανθάνω.ἐπιλαθώμεθα ((mid.)subj.2aor.pl.1.) ← ἐπελαθόμην ((mid.)2aor.) ← ἐπιλανθάνομαι.γυναιξί (f.pl.dat.) ← γυνή,この名詞の変化は練習 9 の単語リストを参照.

おそらく実現可能な未来の仮定 (§116.1) であり,そうすると後文 (ἐπιλαθώμεθα) には直説法未来または命令法が用いられるはずであるが,未来のことがらに対する危惧・恐怖の文 (§139.2) によって接続法に変えられている.その際,接続法においてはもはや時称は動作態(アスペクト)の相違を表すものでしかないため (§113),一回的行為としてアオリストが用いられていると考えられる.なお,完了と未来完了は本時称,過去完了は副時称である (Ciesko 8§67).

31-6. 噂好きな人というのは,このような人である:友人に出会い,ただちにほほえんで尋ねる,「君はどこから(きて),いかにしてその状態であるのか,そしてこのことについてある新しいことを言うことができるか?」すると(友人は)ほうっておかずに答えて言う,「君はなにを言っているのか.君は何をも聞いていなかったのか.私にとって,君を新しい噂でもてなすことはよいと思われるのだ.」

正直あまりよくわからなかった.最後の文は,おそらく「新しい噂があるよ」ということが言いたいのだと思われる.

ἀπαντήσᾱς (1aor.part.m.sg.nom.) ← ἀπαντάω.μειδιάσᾱς(マクロン省略)(1aor.part.m.sg.nom.) ← μειδιάω.ἐρωτῆσαι (1aor.inf.) ← ἐρωτάω.ἐάσᾱς(マクロン省略)(1aor.part.m.sg.nom.) ← ἐάω.εἰπεῖν (2aor.inf.) ← εἶπον (2aor.).ἀποκρίνασθαι(マクロン省略)((mid.)1aor.inf.; 流音幹のため σ が脱落: §38.3) ← ἀποκρίνομαι(マクロン省略).

ἀκήκοας (2perf.sg.2.) ← ἀκούω.この動詞はアッティカ式畳音という畳音を行っている (Ciesko 7§24).まず語頭の母音 + 子音を重複させ,次に α, ε を η に,ο を ω にする;ἀκ → ἀκακ → ἀκηκ.時称接尾辞は -α- で第2完了である.υ はなんやかんやあって消滅する.

*1:ἀμὴν λέγω ὑμῖν