haskell-jp / questions #78

前悩んだ時は LANG=C で言語指定したらビルドできました
フォローアップを忘れていました。have-quartz-gtkフラグが必要です。cabalなら
cabal build --with-gcc=gcc-9 --constraint="gtk +have-quartz-gtk" でいけると思います。
ちなみに`cabal install gtk --with-gcc=gcc-9` を試されていますがcabal v3以降ではプロジェクト外での cabal install は実行ファイルをインストールするコマンドです。ライブラリをインストールする場合は cabal install --lib を使う必要があります。
競プロ用に`Data.Vector.Fusion.Bundle.Monadic`を弄っていて,
-- | Monadic streams
data Bundle m v a = Bundle { sElems  :: Stream m a
                           , sChunks :: Stream m (Chunk v a)
                           , sVector :: Maybe (v a)
                           , sSize   :: Size
                           }

を見たんですが,この第三フィールド(`sVector`),なんで存在するのか分かる方っていらっしゃいます? Data.Vector.Generic.unstreamでさえこれを消費しているように見えないので,本当になんのためにあるのか分からなくて…….
@ has joined the channel
詳しいことは分からないですが sVector ができた経緯としては fromVector でもらった vector をそのまま保存するためみたいですね
https://github.com/haskell/vector/commit/f375eff766f1fbecfc2944da3a7034c22658590a#diff-a5466f1eaf4aa39e68b2095915f3fde1L1590-R1594
試しに sVector を消してコンパイル通してみましたが、確かに取り出してないように見えますね
https://github.com/haskell/vector/compare/master...kakkun61:remove-svector
ですよね…。ありがとうございます。まあ、fromVectorで代入されてるのは見てるんですけど、やっぱよくわからないですね…。外部ライブラリで使用させてあげるためとか? それとも歴史的な理由か…。
英語で聞くのは大変かとは思いますがどうやらここにvectorパッケージのメンテナはいないようなので
https://github.com/haskell/vector/issues か適当なML(恐らく[email protected] あたり?)で聞かないとこれ以上のことはわからないと思います:disappointed_relieved:
@iwataka has joined the channel
ですよね……….でも,英語で聞くのは問題ないんですが,「存在することに問題(issue)がある」というふうには思えなかったので,とりあえずここで聞いてみたんですよね
と思ったけど,issueはproblemじゃないんだから,バグでも改善点でもない単なる疑問点でも聞いていいのか………?
「存在することに問題(issue)」は十分ありえますよ。余計なフィールド(実際にはまだ容疑だけですが)があると言うことはそれだけでこうして意味を調べる時間を割かないといけない原因になりますし、新しい機能を追加したりするときに検討事項を増やす要因になり得ます。
ユーザーに直接影響を与えることは(多分)ないでしょうがメンテナンスの負荷を多かれ少なかれ上げることになるので立派な問題だと思います。
https://github.com/haskell/vector/issues/269 とりあえずissueにしました.
正直忙しそうで申し訳ないのですけどね………
@ has joined the channel
@Daikichi has joined the channel
@ちくわ has joined the channel
基本的なことなのですが、たとえば
main :: IO ()
main = do
                 putStrLn “string”
                 putStrLn “string”

がメモイズされないのってなぜですか?
IO独自で阻害する何かがあるのか、もっと一般的なことなのでしょうか。
何がメモ化されるべきだと考えているのですか?
一つ目の putStrLn "string" がメモ化されて1回しか出力されないのでは、という話ですかね?
そうです!
メモ化されるべきではないですが、メモ化されるべきではないという明示がない同引数の関数をメモ化していないのはIO自体に細工があるのでしょうか?
うーん。フィボナッチの計算などでいうメモ化のことであれば、Haskellでもメモ化のためのライブラリなどを使わないとメモ化されないと思います。
あれ、そうでしたっけ。
資料ありがとうございます。
読んでみます。

もう少しHaskellのメモ化戦略について調べてみますorz
(もう回答済みで恐縮ですが)そもそも、別々の場所にあるたまたま同じ形の式が自動でメモ化されるなんてことはありません。
じゃぁどういう条件だとメモ化されるの、というと、結構複雑です、こちらのスレッドや記事なども参考にどうぞ、とだけ :sweat_smile:
https://haskell-jp.slack.com/archives/C5666B6BB/p1564340963043600
http://www.kotha.net/hperf/basics.html
https://kakkun61.hatenablog.com/entry/2019/07/29/%E9%96%A2%E6%95%B0%E3%81%AE%E3%83%A1%E3%83%A2%E5%8C%96
たぶん、メモイズが提供される高階関数とHaskell自体の機能を混同してました。
ありがとうございました。

https://stackoverflow.com/questions/13059381/an-option-to-make-memoization-the-default-behaviour-of-haskell
自動的にメモ化されるとなると、コンパイラが動的計画法を自動的に実装してくれることになりますが、一般的にそんなことはしません。
資料ありがとうございます!
助かります!
すみません、高階関数の機能ではなくcommon subexpression eliminationについてでした!

So GHC does do CSE, but only in specific circumstances --- see the GHC manual. (Section??)
詳細への参照が「セクション??」になってます笑

単純にこのIOのケースではCSEは動かないし、そんなにCSEが動く場面はないよ、ということでした。

https://wiki.haskell.org/GHC_optimisations#Common_subexpression_elimination
ところで,CSE が動けば IO はメモ化されますが,IO のメモ化とIO effect のメモ化は異なる概念なので,effect がメモ化されるわけではありません:
main = let e = putStrLn "string" in e >> e

で,e の二回目の呼び出しは (最適化を考えなければ)メモ化されますが, string は2回出力されます.GHC の場合,IO は単純な State モナドで実装されているので,e は状態操作関数が束縛されていると思えば良くて,状態操作関数をメモ化したところで,関数の実行は2回行われるので作用は2回行われるというのが,作用がメモ化されない要因ですね
(ただし,この前提は最適化次第では崩れる場合があり,特にインライン展開の順番には GHC は気を使っていて,IO 相当の状態操作関数はインライン展開が幾つか阻害される場合があります)
最適化を考えない場合の話は,State モナドでも同様なので,State モナドの作用がメモ化されないのはなぜか考えてみるのがいい気がします
@Alex Sayers has joined the channel
@iwase has joined the channel
ぽんちゃん
stackでgccを指定するやり方がちょっと調べてもわからないんですよね、、


いただいたbuildコマンドを試したところ
unrecognized 'build' option `--constraint=gtk +have-quartz-gtk'

と言うエラーが出ました。

cabalのバージョンが
cabal-install version 2.4.1.0
compiled using version 2.4.1.0 of the Cabal library 

遅れてるのでしょうか?
@liveinwood has joined the channel
@fujino has joined the channel
参照透過性に関する質問です

関数内で定義された関数にて、外側の関数の引数を(引数を経由するのではなく)利用している場合、その内側の関数は参照透過性があるといえるのでしょうか
その関数が実行される状況では“外側の関数の引数“は決まっているので透過性がありそうなものの、引数以外のデータに依存しているのでどうなのだろうと思っています。

具体例としては、以下のようなコードで、 gは参照透過性があると言えるのでしょうか

f :: Int -> String
f x = let g = if x == 0
                    then "empty"
                    else (show x)
         in g


又、以下のようにすれば確実に参照透過性が保たれると思うのですが、そこまでして参照透過性を保った方がいいのでしょうか

f :: Int -> String
f x = let g a = if a == 0
                    then "empty"
                    else (show a)
         in g x
外側の関数の引数(変数)は定数扱いとかそんな感じっぽそう
クロージャとかカリー化とかで調べたら答えがわかりそう
そんなことなさそう...
自分も、外側は定数として扱えるのかな〜とも思ったりしたのですがどうなんですかね…
とりあえず、設計するときにどっちの方が好まれるのかが気になっています。
@ has joined the channel
とりあえず、設計するときにどっちの方が好まれるのかが気になっています。
その意味ですと、どちらも一長一短あるのでなんともいえないですね...
最適化のしやすさも絡んでいたような...

個人的には積極的に自由変数として参照する方が、少なくとも書くのは楽なんで好きですが。
ほかの方の意見も気になります。
(なので、「Also sent to the channel」しました)
この例のようにローカルでない変数を参照していたとしても、その変数もまた参照透過性があるので、参照透過性が損なわれることを心配する必要はありません(cf. https://en.wikipedia.org/wiki/Referential_transparency#Examples_and_counterexamples)。余分な引数を減らすことはプログラムの高速化につながるので積極的にやっていきましょう
Template Haskellの [e| |] について、:point_down: のようなちょっと面白い挙動を見つけたんですが、これはどこのドキュメントに書かれているでしょうか?

Template Haskellのマクロを定義しているコード: Lib.hs
{-# LANGUAGE TemplateHaskell #-}

module Lib where

import  (ExpQ)

-- definedInMainはLib.hsでは定義されてない!
expq :: ExpQ
expq = [e| putStrLn definedInMain |]

Lib.hsが定義したマクロを展開するコード: test.hs
{-# LANGUAGE TemplateHaskell #-}

import Lib

main :: IO ()
main = do
  -- 代わりに、test.hsで定義する
  let definedInMain = "hello!"
  $(expq)

というLib.hsとtest.hsを書いたとき、Lib.hsの [e| putStrLn definedInMain |] で定義されていない、 definedInMain をマクロを展開しているtest.hsから参照する、という挙動です。
なるほど!みなさんありがとうございます!
--constraintオプションがいつからあったのかはわかりませんが、cabal-installは古いGHCでも使えるので、常に最新のバージョンを使うのがおすすめです。
質問がよく分かってないですが,
haskell
>>> :set -XTemplateHaskell
>>> import 
>>> let e = () in $(unboundVarE $ mkName "e")
()

が面白い挙動ということですか?