Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

乱数系関数の提案 #676

Open
4 tasks
salano-ym opened this issue May 20, 2024 · 17 comments
Open
4 tasks

乱数系関数の提案 #676

salano-ym opened this issue May 20, 2024 · 17 comments

Comments

@salano-ym
Copy link
Member

salano-ym commented May 20, 2024

  • Rand:choice(a: arr<value>, rand?: fn): value
    配列からランダムに1個取り出す
  • Rand:choices(a: arr<value>, count: num, rand?: fn): arr<value>
    配列からランダムにcount個取り出す(重複有)
  • Rand:sample(a: arr<value>, count: num, rand?: fn): arr<value>
    配列からランダムにcount個取り出す(重複無)
  • Rand:shuffle(a: arr<value>, rand?: fn): null
    配列をシャッフルする
@FineArchs
Copy link
Member

配列の組み込みプロパティにしたほうが書きやすそうな気も?

@salano-ym
Copy link
Member Author

配列の組み込みプロパティにしたほうが書きやすそうな気も?

あんまりプロパティに詰め込むと依存度も上がって良くないかなという考えです

@FineArchs
Copy link
Member

依存度

詳しく聞いてもいいですか?

@salano-ym
Copy link
Member Author

依存度

ニュアンスとしては乱数側に所属させてもっと抽象的にシーケンス的なものを対象にしたいという感じ
rand.choice(v: sequence<value>): value

@salano-ym
Copy link
Member Author

salano-ym commented May 20, 2024

ハードコードの組み込み以外で型を増やせる仕組みが欲しいところ…

@FineArchs
Copy link
Member

シーケンス的なもの=JSのiterableみたいなものですかね?
それならシーケンス的なものにもれなく.choiseなどを継承させるやり方の方が私としては好みです
チェインさせやすいですし、イメージ的にこれらの関数は乱数よりも配列が主体なように思います
まあエイリアスとして両方用意してもいい気がします

@salano-ym
Copy link
Member Author

salano-ym commented May 20, 2024

他の言語でもrand.choice(seq)の形式が多いように思います
各シーケンスの内部実装に依存させるのではなく汎化されたインターフェースを通じて処理する方針です

@FineArchs
Copy link
Member

FineArchs commented May 20, 2024

他の言語でもrand.choice(seq)の形式が多いように思います

あら、そうですか?python以外ではあまりイメージがないですが、事例があれば教えて下さい。

各シーケンスの内部実装に依存させるのではなく汎化されたインターフェースを通じて処理する方針です

その点では、各シーケンス的なものの上位クラスで定義されたメソッドを下位でそのまま受け継いでも独自で拡張してもよいようにした方が柔軟性が高くなると思います。

@salano-ym
Copy link
Member Author

事例があれば教えて下さい。

調べた範囲ではchoice相当の関数が明確に配列側に所属しているのはRubyとSwiftだけでした。

配列からランダムに取り出す関数がどこに所属するか
  • 配列に所属
    • Ruby
    • Swift
    • Kotlin (.shuffle)
    • Dart (.shuffle)
  • 配列に所属しない
    • C#
    • Python
    • Rust
    • PHP
    • Julia
    • D
    • Nim
    • Scala (.shuffle)
    • C++ (algorithm::)
  • 対象関数が無い(添字を経由する等)
    • C
    • Java
    • JavaScript
    • Perl
    • Go
    • Lua

@salano-ym
Copy link
Member Author

salano-ym commented May 21, 2024

各シーケンス的なものの上位クラスで定義されたメソッドを下位でそのまま受け継いでも独自で拡張

シーケンスごとの実装に任せるということは乱択アルゴリズム自体を任せてしまうということなので、等価なシーケンスでも結果が変わってしまう可能性があります。
乱数側で処理する方がシーケンス側の責任も減って結果の一貫性を保ちやすいかと思います。

@FineArchs
Copy link
Member

調べた範囲ではchoice相当の関数が明確に配列側に所属しているのはRubyとSwiftだけでした。

確かにそうみたいですね…

シーケンスごとの実装に任せるということは乱択アルゴリズム自体を任せてしまうということなので、等価なシーケンスでも結果が変わってしまう可能性があります。

任せるのではなく変えてもよいとする余地を作るのが継承です。
多くの場合は共通のアルゴリズムを使うのがよいでしょうが、シーケンスの仕組み次第では既存の仕組みが非効率になってしまうこともあるでしょう。

@salano-ym
Copy link
Member Author

任せるのではなく変えてもよいとする余地を作る

変更できてしまうのが問題と思います。
選択アルゴリズムを具体的に指定しない限り結果の一貫性を保つのは難しいです。

シーケンスの仕組み次第では既存の仕組みが非効率

結果を変えずに、乱択の段階で行う必要のある最適化が思いつきません。
例えばArrayListとLinkedListの参照効率の違いであれば最適化はイテレートの段階で行うべきです。
結果が変わるような最適化であればアルゴリズムを別途指定できるようにする方がいいと思います。

@salano-ym
Copy link
Member Author

salano-ym commented May 21, 2024

実装されてないOOPに話が逸れましたが、
要するに基本的な対象である組み込み値にあれこれ生やしすぎたくないという気持ちです。
単にチェーンの形式で書きたいというだけなら特定のオブジェクトに所属させるよりもUFCSのような糖衣構文を導入する方が健全なように思います。

@FineArchs
Copy link
Member

選択アルゴリズムを具体的に指定しない限り結果の一貫性を保つのは難しいです。

元になるシーケンスの仕組みが違うのに結果に一貫性を持たせる必要性は薄いように思います。
どうしても結果に一貫性を持たせる手段を用意したいというのであればやはりrand.choisearr.choiseも両方用意するのが妥当かと思います。

結果を変えずに、乱択の段階で行う必要のある最適化が思いつきません。

抽象化されたシーケンスには長さが無限になるものもあると思いますが、そのようなシーケンスは通常のアルゴリズムで乱択すると時間が無限にかかってしまいます。

要するに基本的な対象である組み込み値にあれこれ生やしすぎたくないという気持ちです。

むしろ基本的な対象こそ様々な機能を生やして便利にすべきでは?だからこそこれまで組み込みプロパティを増やす方向で進めてきていたものと思っていましたが

単にチェーンの形式で書きたいというだけならUFCSのような糖衣構文を導入する方が健全なように思います。

それは以前からやりたいと考えていましたが、要するに組み込みプロパティをユーザー側でも定義できるようにするということですから健全性の観点でいうと特にメリットはないのではと思います。

@salano-ym
Copy link
Member Author

元になるシーケンスの仕組みが違うのに結果に一貫性を持たせる必要性は薄いように思います

ArrayListかLinkedListかのような内部実装が結果に影響するのが良いとは思いません。気軽に変更できてほしいです。
(全員で同じ問題をする日替わりゲーム等がリファクタリングで違うものが出てくると困るので)

抽象化されたシーケンスには長さが無限になるものもある

有限か無限かは停止性にも関わってくるので最適化というより根本的なアルゴリズム自体が変わると思います。
いくつか他言語の実装を見ましたが、有限でランダムアクセス可能なもの(≒配列)のみを対象にしていました。

基本的な対象こそ様々な機能を生やして便利にすべきでは?

個人的には1オブジェクトの責任は小さくあってほしい主義です。(プロジェクト自体の方針は把握してませんが……)

組み込みプロパティをユーザー側でも定義できるようにする

ただの関数をメソッド呼び出しのように書けるようにするものなのでプロパティに追加して所属させるのとは別物です(是非は別として)。

@FineArchs
Copy link
Member

まあ色々ありますが、それら全てをひっくるめてもチェインの形で書けるメリットが上回ると思います。
ネストが増えるのは悪です。

@FineArchs
Copy link
Member

ArrayListかLinkedListかのような内部実装が結果に影響するのが良いとは思いません。気軽に変更できてほしいです。
(全員で同じ問題をする日替わりゲーム等がリファクタリングで違うものが出てくると困るので)

確かにその点だけ見るとプラスマイナスでいえばマイナスでしょうが、マイナス幅は小さいと思います。
日替わりゲームの例で言うなら、そもそもリファクタリングするのにアルゴリズムが変わらない場合のほうが少ないのではないでしょうか?

有限か無限かは停止性にも関わってくるので最適化というより根本的なアルゴリズム自体が変わると思います。
いくつか他言語の実装を見ましたが、有限でランダムアクセス可能なもの(≒配列)のみを対象にしていました。

アルゴリズムが異なっていても、例えばchoiceなら「シーケンス状のものから乱数番目の要素を取得する」という共通部分を持った動作が同じ名前で呼び出せるというのは直感性・学習容易性において大きなアドバンテージになると考えられます。
また、これはもっと早く言及すべきでしたが、AiScriptは他の言語の真似をするために作られた言語ではないはずですから、他言語を参考にするのはそうしなければ天秤がどちらにも傾かないような場合のみに限るべきではないでしょうか?

個人的には1オブジェクトの責任は小さくあってほしい主義です。(プロジェクト自体の方針は把握してませんが……)

ただの関数をメソッド呼び出しのように書けるようにするものなのでプロパティに追加して所属させるのとは別物です(是非は別として)。

着火した身でいうのもアレですが、本筋にあまり関わらなそうなのと長文しか出せない気がするのと論点を絞りたいのとでこの場では返答を割愛します。(また機会があれば・・・)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants