haskell-jp / random #27

はい,let-束縛で変数を束縛するのは値ではなく,計算であるというのは理解できました.
「サンク」であることと「停止しない計算」とは区別できないように思いますがどうでしょう.
それと,let x = 1 のときx に束縛されるのは 1 という式で表される計算であって,値ではないと考えていいように思います.
オブジェクトは大きく分けて2種類ある
計算の1種類だけでよいような気がしますがどうですか?
「サンク」であることと「停止しない計算」とは区別できないように思いますがどうでしょう.
Haskellの関数は基本的には値を取るため、オブジェクトがサンクかどうかを判定することはできません(GHCにはunpackClosure#のような例外あり)が、書き手が区別しないわけではないというのが重要だと思います。
計算の1種類だけでよいような気がしますがどうですか?
サンクは計算を指し示していますが、計算そのものとは別に扱うべきで、実際のモデルと乖離した定義をする(GHCなら17種類あるものを全部"計算"と呼ぶ)ことには賛成できません。
本文中では、「代入が」オブジェクトに関するものだとしており、この束縛と計算の議論とは直接関係ないので、あえてオブジェクトの定義に触れる必要はないと思います。
ああ.またやらかしました.すみません.変数にバインドできるものをオブジェクトと読んでしまってました.
評価完了していない値を_|_と書くのは、Wikipediaに載ってる不動点意味論の流儀なのかなあと思うのですが、確かにHaskellの一般的な用法とちょっと違う感じがしますね https://ja.wikipedia.org/wiki/%E8%A1%A8%E7%A4%BA%E7%9A%84%E6%84%8F%E5%91%B3%E8%AB%96
評価完了していない値を_|_と書くのは、Wikipediaに載ってる不動点意味論の流儀なのかなあと思うのですが
なるほど、これは僕の勉強不足でした :bow:
QuasiQuoteのいい活用方法だと思う。
https://github.com/ryota-ka/duration
@ has joined the channel
⊥の話は,R.Bird "Introduction to Functional Programming using Haskell" に少し出てきます.
CI したい
Haskellでは let x = 1 2 はxに(1 2を計算した)値を束縛しているのではなく,言うとしたら(call by name的には)1 2という式自体への束縛,または(call by need的には)1 2という計算自体への束縛というのが正しいと思います(なので記事の値への束縛というのが誤った使用法というのはHaskellでは誤りというのに同意です).

「変数の値へのバインド」ではcall-by-needを実現できないということでしょうか?変数と値の対(バインディング)のリストを環境として,式を環境下で解釈して値を得る意味関数ではcall-by-need流の意味論を構成できないということでしょうか?
議論が後退している気がします。値をバインドするとしてしまうと、評価していないものをバインドできない(したがってcall-by-needにならない)というのは本文でもこの議論でも触れたとおりです。
また、「λ変数」「意味関数」のような一般的に使われていない用語を定義せずに持ち込むのは、議論が困難になるので避けていただきたいです
また、「λ変数」「意味関数」のような一般的に使われていない用語を定義せずに持ち込むのは、議論が困難になるので避けていただきたいです
すみません.「λ変数」は「束縛変数」,「意味関数」は「評価器」と読みかえてください.今後は,この用語は使いません.
値をバインドするとしてしまうと、評価していものをバインドできない(したがってcall-by-needにならない)というのは本文でもこの議論でも触れたとおりです。
ここのところは「値をバインドするとしてしまうとcall-by-needになるような評価器を作成できない」と解釈してもいいですか?
はい、実装してみようとしてみるとできないことが比較的簡単にわかると思います
ありがとうございます.ちょっとやってみます.
deriving via句にMonadReaderが出てきて :thinking_face: ってなったけど、capabilityのMonadReader m aはm aのnewtypeなのか!
Lazyな(おもちゃ)言語を作ってみました.
変数を値にバインドしたバインディングのリストで環境を構成しています.
Bindの定義を見るとわかる通り、これは変数名と「Valueの計算」の対(タプルは要素について非正格なため)になっていますね
「Value」と「Valueの計算」は別ものですか?
別物であるがゆえに、その評価器はcall-by-needを実現しています。
どうやって区別するのですか?
タプルはその要素が値である必要はなく、サンクも入れることができます。 を使えばプログラムの中で判別することもできますよ。
書くのに全く区別を意識したわけではなです.
区別を意識して実装しなければ議論が成り立ちません。
区別する必要が全くなかったので意識しませんでした.私が議論が理解できなかったのはそこですね.なぜ区別するのかが判らないんです.
申し訳ないのですが、これ以上議論を進められる気がしないのでこれ以上のコメント(おそらく同じ説明を繰り返すことになるでしょう)は控えさせていただきます。
はい.ここからは,自分で考えてみたいとおもいます.長々とお付き合いいただきありがとうございます.
おそらく実装する言語を正格な言語(例えばRustやOCamlなど)にしてみるのがいいのではないでしょうか?
正格な言語を使えば意識せざるを得ないだろうことは想像できますが,非正格の言語を使うときにどう考えるのかという話であったように思います.それで,ふつうにHaskellで実装しました.Haskellを使っている限りにおいて意識しませんし,しなくてよいのではという思いが私の根底にあるようです.だからこそ,Haskellを使っているのに何故,意識しなければならないのかを理解したかったのです.
式が評価ずみであろうが評価中であろうが,式が表す値は値だという考え方に,何か不都合があるのならそれを知りたかったということです.アドバイスありがとうございます.
うーん、ではcall by valueを実装してみればよいのでは無いでしょうか?今回のはHaskellで意識しなくていいという話というより、たまたまHaskellでcall by needの実装だったからだと思います
Haskellから機械語へのコンパイラをHaskellで作れば絶対に理解できます。
Haskellから機械語へのコンパイラをHaskellで作れば絶対に理解できます。
はい,是非挑戦してみたいです.

call by valueを実装してみればよいのでは無いでしょうか?
これもちょっとやってみます.
call-by-valueを実装してみました.
本質的に変更したのは,関数適用式の評価に際して,関数部分の式を評価して得られる関数値を,引数部分の式を評価して得られる値に「正格に」適用しただけです.もう一箇所,Valueの関数ではない方は,裸のIntと同型になるようにbangを付けています.これはLazyの方も修正してあり,Valueの定義自身は両方で同じです.
https://github.com/tweag/capability/blob/f1529d502d7c6a3c3eb0feaf488973999b3f6297/src/Capability/Reader/Internal/Strategies.hs#L47 のことね。
(こういうときは該当のソースを表示させているときに「y」を押すといい)
通常call by valueでは,let x = e in e’ ~ (\x -> e’) eな気がするので,let bot = bot in botが無限ループしないのはあまりcall by valueと言えない気がします
あらら.
手元では無限ループしますが...doctestの記述を修正しわすれた.
あ,すいません.無限ループしますね.ちょっと勘違いでした.言いたかったのは次のパターンですね
eval $ Let [("bot",Div (Con 1) (Con 0))] (Con 0)

これがexceptionを吐かないのはおかしな気がします
あちゃーっ!!
修正.Valueの関数を正格関数として生成.interpの際はそのまま適用.