見てもらったほうが早いかもしれません。$time("朝の通勤時間")、電車の窓から、隅田川の$season("桜")が見えた。}上の例では、シーンが満たす「制約」として季節(season)は「春」である。時刻(time)は「午前」である。本文では、この制約を明示的に満たすように注釈(annotation)することが求められます(しないとコンパイル時にエラー)。$time("朝の通学時間")という箇所は、time制約の「午前」を「朝の通学時間」と描写することで満たそうとしています。同様に$season("桜")も、season制約の「春」を「桜」と描写することで満たそうとしています。いう風に「各シーンに課した制約を注釈しないとコンパイルエラー」とすることで、書き手は自分が何を書かなければならないのかについて、常に自覚的になることを強制されます。ちなみに制約は別に時間に限らず、何を設定するのも作者の自由です。person:"花子"とか。シーンの設計図を事前に自覚的に書く、というのが重要なところです。先の時間描写が不足している件ですが、おそらくアマチュアの作者は、自分の頭の中では「午前か午後か」「平日か休日か」「春か夏か」などを、ちゃんと思い浮かべていることが多いのではないかと思います。それは、書かなければ第三者には伝わりません。各シーンに明示的に「客観的な事実」を宣言するというお作法を強要し、かつそれを説明しないとコンパイルが通らない、というアプローチをとり、作者の客観的な自覚を促そうとしているわけです。プログラマもよく、色々なチョンボをやらかして、コンパイラに叱られます。煩わしいけど、それによって正確なプログラムが書けるようになるわけです。小説って、基本的には誰の力も借りずに黙々と書くものじゃないですか(違ったらすみません)。したら、こういう方法でコンピューターを「機械編集者」のように利用するというのは、プログラムの質を上げるのと同じように、作品の品質を上げ得るのではないでしょうか。作者とプラットフォームのWinWin実はこの仕組みを導入することは、作者とプラットフォーム運営者(出版社や投稿サイト)の双方に利益があります。作者はこの言語を使うことで、作品の質を上げることができますが、同時にプラットフォーム側も「注釈付きのHTML」を入稿してもらうことで「自然言語処理」がしやすい原稿データを取得できるのです。$season("桜")が満開だ。}次のようなHTMLを出力します(ちなみに出力HTMLのタグや属性についてはtnconfig.jsonという設定ファイルで設定できます)。<season>桜</season>が満開だ。</scene>これは自然言語処理にとっては有利です。生のテキストで「桜が満開だ」という情報から「春」という情報を機械的に取得するのは、なかなか面倒なことです。我々がよく知る小説原稿のテキストは、あまりに形式として素朴すぎるため、自然言語処理と相性がよくないのです。出力結果が上記のようなマークアップなら、最初から作者がさまざまな情報を注釈してくれているのですから、格段に仕事が簡単になります。なにより、質の良い機械学習用のデータとしても利活用できそうではありませんか。世の中の検索エンジンは、HTMLに意味情報を含ませることで(セマンティック・ウェブ)、検索精度を向上させてきました。小説のように「素朴な形式」で書かれる媒体も、時代とともに意味情報を含んだ形式(セマンティック・ノベル)に進化していくのではないかなあと思っています。後述しますが、この「セマンティック・ノベル」については、個人的に仕様を模索している最中です。インストール(2019/10/14日追加)npmからインストールできます。色々なオプションがありますが、基本的には次のような感じで大丈夫でしょう。mynovel.tn上のようにすると標準出力にHTMLが出力されます。--helpで確認できます。出力HTMLのタグを変えるには詳しくはドキュメントを読んでもらうこととして、簡単に言うとtnconfig.jsonというファイルを編集することで、出力するHTMLタグを自由に編集することができます。tnconfig.jsonというのは、もちろんTypescriptのtsconfig.jsonを真似したものです。最初はそんなファイルはないので、コマンドラインから次のコマンドで作成します。--initこうすると、現在のディレクトリに初期設定で書かれたtnconfig.jsonが出力されます。このファイルのmarkupMapという欄を編集すると、色々とタグを変えることができます。class='scene'>にしたかったら、次のようにします。}}上記で<name>とありますが、これはプレースホルダーといって、@sceneタグに使うと、sceneという文字列に変更されます。<indexOfType>とか色々なプレースホルダーがあります。詳しくはCheatsheetのページで確認してください。開発言語:F#開発言語なのですが、今回は実行ファイル(コンパイラ)を配布するのがメインなので、Win/Mac/LinuxにクロスコンパイルできるF#を採用しました。F#はちょっとマイナーな言語?なのかもしれませんが、OCamlとよく似て非常に言語処理系が書きやすい言語です。久しぶりに触ってみたら、色々な周辺ツールがよく整備されていて驚きました。.NETの資産も活用できるので、生産性も高いし、パッケージマネージャーNugetも使いやすくていい感じです。Update)TypeNovelをTypeScriptで書き直しました今後の展望TypeNovelと並行して、SemanticNovelという仕様と、そのビューアーについて構想中です。SemanticNovelのビューアーは、例えばシーンの切り替わるタイミングで改ページが入る。シーンの時刻に応じてビューアーのテーマが変わる(夜ならダークモードとか)。各セリフが誰によるものなのかを明示する補助UIなどなど、作品の「文脈情報」を生かし、読者に親切な読書環境を提供することを目指して開発しています。仕様をきっちり作っておかねばなりません。時間がかかるかもです。縦書き文庫にも導入できたらなあと妄想しています。Code拡張を公開しました最後にTypeNovelのリポジトリはオープンソースで公開されています。興味のある方はお気軽にご参加ください。https://github.com/tategakibunko/TypeNovelSemanticNovelについても、一応Githubに場所を用意しておきました。更新していく予定です。公開した件についてTweet広告を非表示にするもっと読むコメントを書く2019-02-09投稿画面からプレビューできるボタンを復活させました縦書き文庫やはりプレビューが使えないと色々と不便なので、プレビューボタンを復活させました。投稿ボタンの下に「プレビュー」ってボタンがありますので、使ってみてください。プレビューボタンプレビューを押すと、プレビュー結果こんな感じで、簡易ビューアーが表示されます。プレビューボタンが表示されない方は、リロードするか、それでも駄目ならタブを閉じてから開き直してみてください。縦書き文庫をリニューアルしました。新しくなったところ小説投稿画面の機能がスマホでも全て使えるようにこれまではスマホの投稿画面ではルビや太字ぐらいしか選べなかったのですが、すべてのボタンがPCの投稿画面と同様に使えるようになりました。PCだとこんなふうで、PCの投稿画面スマホとかだとこういう感じです。スマホの投稿画面しおりが無制限に挟めるようにこれまでは10個までの制限があったのですが、いくらでも挟めるようになりました。以下は、しおりを入れるボタンしおりを挟む以下はしおりを開くボタンしおりを開くしおりを開くと、しおりの一覧が出るので選択します。しおりの一覧ちなみに、しおりの数に制限はありませんが、一つの作品に大して10個以上の栞を挟んだ場合、直近の10件までが表示されます。マテリアルデザインの採用スマホ等のタッチで操作する端末に親和性が高い(とされている)マテリアルデザインを採用しました。色々な操作がアニメーションするので、操作がより直感的になったのではないでしょうか。シリーズ作品の並び替えがドラッグ・アンド・ドロップに対応シリーズ作品の並び替えも、より直感的にドラッグ・アンド・ドロップで可能になりました。シリーズの並び替えダッシュボードに読んだ、読まれたの情報を表示ダッシュボードページを新設し、作品を読んだ、読まれたの履歴がパッと確認できるようになりました。ダッシュボード「読まれた」のタブには、自作がページ送りされてポイントが入った履歴が出ます。「読んだ」のタブには、自分が他者の作品を読んで得たカルマの履歴が出ます。利用者があまりいないのと、サーバーへの負担を考慮して廃止となりました。一部の古いコードは動くかもしれませんが、動作は保証されません。キャラクターとファンのタブ(プロフィールページ)を廃止スマホの横幅に足りないというのが主な理由なのですが「ファン」についてはPC限定で復活するかもしれません。廃止したのは、表紙の有無が作品のクリック率にあんまり寄与しない(ように見える)ほか、著作権の確認なども大変だったからです。賛否両論あるかもしれませんが、表紙画像をなくすことで、サイトの読み込みも速くなるので、自分としては良かったかなあと思っています。開発の振り返り去年の年末にPCがぶっ壊れてしまったのですが、奇跡的にデータが残ったまま修理が完了したので、そのまま最後まで開発することができました。自分にとっては今回が人生初Angular(とNgrx)だったのですが、すごく開発しやすかったです。Angular+Ngrxでは、状態をObservableで閉じることができるので、論理的に矛盾した状態が作られにくい、というところが素晴らしいと思いました。typescript先月から試験的にAngular+Ngrxを使って縦書き文庫を作り直してみる、ということをしていたんですけど、パソコンが壊れバックアップも取ってなかったので、全て消え去りました(この記事はChromebookで書いてます)。真面目にやると一年ぐらいかかる作業なので、一ヶ月程度の作業で済んだのは不幸中の幸い?なんでしょうかね。Angular+Ngrxの感想としては、コツを掴むまでかなり時間がかかるということと、fluxなんでaction/reducer/state/effectの開発ループを回すのが面倒くさいなあ、ということです。正直なところ「このまま続けるべきか?」と思ってたところなんで、もしかしたら中止できてよかったのかも。学習コストTypescriptとRxに関しては多少ですが経験があったのでなんとかなりそうだったのですが、それ以外に覚えないといけないことが沢山あって大変でした。Angular+Ngrxは大規模なチーム開発に最適などと言われますが、学習コストを嫌ってVueという選択をする人が多いのも、なんとなくわかるような気がします。NgrxについてNgrxを採用すると、とにかくRxでEffectsを書きまくることになるのですが、ここで割とわかりにくい地雷を踏みまくってしまいました。危険なのはストリームを止めちゃう位置にcatchErrorを書いちゃったり、逆にストリームを止めるべきところでdispatch:falseを指定しないで無限ループを仕込んじゃったりとかです。catchErrorの場所まずEffects中のcatchErrorですが、actions$直下のpipeではなく、map中のpipeで宣言しないといけません。GetFooFail({error})));上の例は、fooに対応するactionを直下のactions$からフィルタリングし、そのデータを元にfetchFooでサーバーから何かしらのデータを取得しようとするコードです。この処理の失敗を、action$直下のcatchErrorで補足すると、fetchFooでエラーが起きたときだけじゃなく、大本のactions$で起きたエラーも補足してしまいます。上の例だと、GetFooFailというアクションを出したいのは、fetchFooが失敗したときだけですよね。別のアクションに変化しない副作用Effectsが新しいActionを返さないのにdispatch:falseをデコレーターに設定しないと、永遠にその処理が繰り返されます。false}を忘れると、無限ループです。自分はCPUがうるさくてパソコンが熱くなったので気づきました。自動ビルドで開発してたのですが、開いてる先のタブがいつのまにかCPU使用率100%になっていたりとか。これがパソコンの熱暴走を起こし、寿命を縮めたんじゃないのか、と今では疑っています。materialのコンポーネントのディレクティブにダイレクトに反映させてしまうと、アニメーションが効かなかったり(例えばチェックボックスとか)、一部のUI要素が正しく計算できなくて表示できなくなったり(例えばタブコンポーネントの下線)みたいなことがあります。マテリアルコンポーネントを使用するときは、コンテナーというUIクッションを用意して、マテリアル要素はその下に置くようにします。マテリアルなコンポーネントを含む下層のコンポーネントには「状態のコピー」を渡し、ローカルでその状態を操作させるようにします。しないと、アニメーションが正しく機能しないからです。その上で、子供の最新状態は@Outputを使ってコンテナーに吸い上げます。一元管理された状態を使用して制御できるのはコンテナーUIまでで、そこから下は状態のコピーが作成されることになります。全てが理想通り、とはいかないですね。余談1ちなみに壊れたMacbookの修理はざっくり7万ぐらいとか言われたんですけど、まあ買い直すよりかは、と思って依頼しちゃいました。年末で忙しいから14営業日かかるとのこと。今からだと来年の10日前後?余談2そういえば最近、中国の開発者が「Immutableなんてほとんどのケースで必要ない。本当の未来はshadow-domを使い、素直にmutableな構造で、かつVueっぽいものだ」みたいなコンセプトでなんかフレームワーク作ってて、すごいスターをもらってた記憶があるのですが、名前を忘れました。プログラミングネットでExpressionChangedAfterItHasBeenCheckedErrorを検索すると、よく「子が親の状態を変更するとビューに一貫性がなくなることが警告される」という説明を目にしますが、少し混乱を招きかねない説明なんじゃないかなあと思いました。正確には「Angularが変更検知をする際に行う探索順において、後からチェックされるビューから、先にチェックされるビューの状態を変える処理を書くと警告される」と説明すべきなのではないでしょうか。HTMLには親子関係だけではなく、隣接(兄弟)関係というものがあるからです。親が子より先に探索されるのは当たり前ですが、隣接関係については自明ではありません。次のようなツリーがあったとします。B|CAとBは隣接(sibling)関係で、Cの親はAです。このときCの親であるAがCより先に探索されることは自明ですが、Bはどうでしょうか。Cより先でしょうか、後でしょうか。Angularの変更検知が「幅優先探索」の順で行われるなら、Bが先です。実際のAngularの変更検知順は「深さ優先探索」なので、検知される順に番号をふると、次のようになります。B(3)|C(2)つまりBは、Cよりも「後に」変更検知されるわけです。探索順に置いて最後になるBにおいて、Cが依存するような状態を変更すると(先に確定されたCの状態を後からBが変えることになるので)ExpressionChangedAfterItHasBeenCheckedErrorというやつが出ます(ただし警告してくれるのは開発ビルドのときだけ)。ウェブで見る「親と子」という説明の仕方だと、幅優先か深さ優先かで受け取る人の解釈が曖昧になるので「探索順」を使った説明をしたほうが親切なのではないでしょうか。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。