haskell-jp / questions #17

そのドキュメントを読む限りでは、*.hi とバイナリがあれば、いけそうな感じはするんですよね。
stack でビルドすると、 .stack-work/install/ 以下に必要なものが出力されてるっぽいのですが、この中から必要な部分を抜き出して、他の環境にもっていけないかなー、と妄想してます。
プラットフォームやアーキテクチャは揃っている、という前提で。
ちなみに個人的にはソースコードをNDAを結びつつ渡すのと大差ないだろうと思っているんですが、そこまでしてやりたい理由ってあるんですか?
まさにそこなんですが、提供先にもコードは隠蔽して機能を提供したい、という判断があります。
そのコードがビジネスのコアになっている、ということでして。
:loadってexportされてない関数も読める
そうだったのかー
型宣言の中に :~> という記号を見かけることがあるのですが、これは何者なんでしょうか・・・?
コード例としてはQiitaの以下の記事があります(コメントで質問しているのも私です)
https://qiita.com/cyclone_t/items/8443ed5d4a77f87b1f1b
古い servant で定義されてる型みたいですね(その記事で使われているのは少なくとも)
http://hackage.haskell.org/package/servant-server-0.5/docs/Servant-Server-Internal-Enter.html#t::-126--62-
changelog をみると 0.7 ぐらいで無くなっているかな?
hiのみの公開は仮に可能だったとしてもGHCのバージョンが変わるとビルドできなくなったりするので…隠蔽したい部分だけ.soや.dllにしてFFIで呼ぶのが常道な感じが
hiって、詳しくは知りませんが、インライン展開する関数とかの情報が入っているっぽいので、気密保持の観点でそこまで信用できるかなあという印象もあります
今自分がやっている分野ですと、 type f :~> g = forall a. f a -> g a などのFunctorの自然変換でよく見る type operator に使われていたりします。そちらのQiitaで使われている場合も (forall a. MyAppHandler a -> ExceptT ServantErr IO a) の意味で使われているように思えました
: で始まる記号はただのコンストラクター(ただし中置演算子)ですよー
という、そもそもの疑問なのかなと思いました(ロジック上の意味というよりも)
(違ってるかも
なるほど、了解です。
順当に so や dll にして FFI で呼ぶ方向で話が進みそうです。
型でしたか!特別な演算子かと思いました。
Qiitaの記事は0.9以降に言及されているみたいなので、0.7くらいで廃止されたとするとちょっも不自然な気がします。
調べてみます。
これ () ですね.ちょっと一見複雑なんですが,
newtype f :~> g = NT (forall a. f a -> g a)

みたいな感じです.(実際の定義は, http://hackage.haskell.org/package/natural-transformation-0.4/docs/src/Control-Natural.html#line-51 にあります)

なお,servant 0.12でbreaking changes () があって,現在enterはdeprecatedです.最新のお作法は, http://haskell-servant.readthedocs.io/en/stable/tutorial/Server.html#using-another-monad-for-your-handlers にあります.(Servantはかなりbreaking changesがあるので,半年前の資料でも信用できないことがあって辛いですが,上のチュートリアルは少なくとも最新を保っているので,何か食い違いがあれば上のRead the docsを参照するのがいいと思います)
フムフム…
と言ったはいいですが、かなり理解の範疇を超えています・・・
@kakkun61 さんが書かれている
「`:` で始まる記号はただのコンストラクター(ただし中置演算子)ですよー」
というところは、LANGUAGE TypeOperatorが付いているので : で始まる型を作れるようになっている、と理解しています。
ですので :~> は型なのだ、というところまでは理解できたと思います。
しかしforallが理解できていないので、<@U98QDF5EJ> さんの説明や @ さんの説明が理解不能です・・・
あ,なるほど.servantのAPIが理解できない話だと思ってました.ちゃんと言ってなかったですが,servant 0.13では :~> の使用は非推奨なので,servantを使用する上では気にする必要はないです.その上でですが,この型の理解は具体的な例を考えてみるとなんとなく分かるのではないかと思い,ちょっと書いて見ました
https://gist.github.com/mizunashi-mana/0b7db5fb26704d47c42234a377fdd777
一般に, ~>:~> は型を省略するための記法と思って構いません(まあそれ以上の意味もあるんですが,その辺はnatural transformationで調べてもらう他ないです).どういう場合に省略できるかというと,型が f a -> g a というように最終的に型引数 a をとる2つの型に対しての関数型になってる時で,この時 a は本質的でない場合が多く fg にさえ着目すればいいためそういう場合の省略記号として f ~> g というように用いられます
:~>~> のnewtypeで主にCategory型クラス () というもののインスタンスにするために,わざわざnewtypeにしています.しかし正直ここら辺で益を得てるものは見たことないですね.結局servantでも頑張ってそれを応用したAPIを提供しようとして,結果廃止することにしましたから.
で,もっと技術的な部分ですが,ここの forall はRank N TypesというGHCの拡張機能で使えるキーワードです.調べて感じここの解説が一番分かりやすそうでしたので,ここを読んでみるといいかもしれません
http://sleepomeno.github.io/blog/2014/02/12/Explaining-Haskell-RankNTypes-for-all/
言葉が足りなくてすみません。でも、だいぶ見えてきた気がします。
元々はservantのAPIを調べていたところ、 :~> が出てきて「これは型なのか?それともHaskell言語の予約語(?)、つまりは -> みたいなものなのか???」という疑問が出てきて、どこを調べればいいかを見失った、という背景があります。
教えていただいたリンク先を見てみます。
TypeOperator は普段 Foo a b みたいに宣言する型を、二項演算子記号で表現できる言語拡張なので :~> はライブラリで宣言された「型」って認識で大丈夫です。 GHC.Generics などに、独自定義された TypeOperator の例が沢山あります(自分も順を追って説明すりゃよかった…)
なるほど!そういうことなのですね。
最初の私の質問がかなり言葉が足りなかったと反省しています。どこまで分かっているかを、もっと書くべきでした。
あ,ついでにですが, TypeOperator (型演算子)は:で始まる必要はありません.今回は,元々の ~> と区別するために :~> になってますが,
data a * b = Pair a b

とかも書けます.混同されやすいですが,:を先頭につける必要があるのは値コンストラクタの方で,
data Pair a b = a :* b -- a * b はダメ

みたいな感じです
MIYATA Tadaaki
@MIYATA Tadaaki has joined the channel
@keizo042 has joined the channel
functorの定義にreturnが入っていないのはどうしてですか?(圏論のfunctorの定義的には入って欲しいと思ったんですが)
(専門じゃないから間違ってるかもだけど) Hask 圏の対象は型だからじゃない?
return って型じゃなくて値を持ち上げてない?
確かにそうですね(monadのreturnはunitなんですね)
ありがとうございます
あ、なるほど、returnは自然変換だから多相関数で表現できてて、確かにこの自然変換は一般の関手に要請されるものじゃないですね
Haskellの型システム上、パラメータを持つ型F、任意の型aについて、F aも型になるので、FがFunctorになる条件の一つは必ず満たされます。だからこそ引っ掛かる人が多いのかも…
@watiko has joined the channel
私も今日気になって調べていたのですが下記のページも若干違うまとめ方がされていてわかりやすかったです。
https://wiki.haskell.org/Monad_Transformers
module exportで昔からわからないことがあるんですが
import qualified Data.Text as T
のようにimportしたものを1つのファイルにまとめてprefixを共通させることは出来ますかね?
プレフィクスなしのものはmodule exportで出来るんですが…
as Import.Tみたいに書いても出来ない
import文だけを書いたヘッダーファイルみたいなのを作ってCPPで include すれば一応できます。
最近作っているプロダクトでは試しています。
なるほどCプリプロセッサですか…1行2行なのでCPPプラグマ追加するのとimport書くのは同じぐらいの行数なので悩みどころですね…
いまいちやりたいことピンと来てないんですが、まとめて reexport は qualified ぬけばできません?
まとめてreexport自体は出来ているんです
プレフィクスを維持したままreexportが出来ないんですよね
:point_down: の部分だけをプロジェクトで共通して利用したい、って話ですよね?
import qualified Data.Text as T
import Other.Module (available, functions)
import qualified Qualified.Module as ReusableShortName
....

繰り返しになりますが、私が知る限り今それをやる一番簡単な方法はCPPです。
そうです
ありがとうございます
import側で共通のprefixを付けるのでは。。。ダメですか?
今回のようにごく小さなケースではそれで十分かと思いますが、個人的には大きなプロジェクト、特に複数人が関わるようになると難しくなるだろうと考えています(だからCPPを使った方法を試してます)。
規約を作って守らせるぐらいなら、自動で統一できた方がいいに決まってるし、プロジェクトの中でのコードのコピペしやすさも高まります。