haskell-jp / beginners #25 at 2024-08-23 12:03:11 +0900

曖昧な質問となってしまい申し訳ありませんが

https://zenn.dev/osio/articles/2022-advent-calendar
に、以下のようなものがありました。
import Control.Monad (join)
f = join
f (*) 5 --> 25 = 5 * 5

Hoogle で join を調べ以下のような定義ということがわかりました。
join              :: (Monad m) => m (m a) -> m a
join x            =  x >>= id

これらをまとめると、以下になると思います。
join (*) = (*) >>= id

しばらく考えて、なんとなく関数モナドかなと思い、定義に当てはめて
h >>= f = \w -> id ((*) w) w

ここに引数を与えて、最終的に
id ((*) 5) 5 ==> (*) 5 5

と、ここまできてようやく納得できました。

前置きが長くなりましたが、`(*)` が関数であるため関数モナドに決まってるでしょ。

と、言われてしまえばそれまでなのですが、`(*)
= id` のようなものを見て、それが関数モナド ((->) r) であると導き出すのは経験しかないのでしょうか ?
型推論の結果で決まるものなので、自力で導き出すには型推論のアルゴリズムを覚えて自分で手計算してみるのが一番近道じゃないでしょうか。
そりゃあ何度もやっていれば経験やら勘やらで素早く導けるようになるとは思いますが、決して職人芸ではなく決められたアルゴリズムで定まるものなので。
答えにくい質問をしてしまってすみません :man-bowing:

型推論のアルゴリズムについて検索してみましたが、理解できるようにも思えませんでしたので、いろいろと試してみます。

ご回答ありがとうございました。
型推論についてはお馴染みTAPLをはじめ、本もいくつか出ていたはずなので詳しい解説が見たいときはそちらも読んでみてください。
join :: m (m a) -> m a
* :: b -> b -> b
join (*)
この3つから m (m a)b -> b -> b ということが分かって
b -> b -> b(->) b ((->) b b) の中置記法だなということを合わせると
(->) b ((->) b b)
^^^^^^  ^^^^^^ ^
  m    (  m    a)

となって m(->) b、`a` ≡ b だなということが分かります
join* も型が明記されてるし型推論は関係ないんじゃないかな(ただの型検査)
(あーでも型引数を具体型にするのは推論か?
確かにこのケースに関して言えば半ば自明な処理ではありますが、定義上立派な型推論ではないかと…
ご回答ありがとうございます。
手順も明記していただきわかりやすかったです :grinning:

教えていただいた手順を参考に、改めて整理して考えてみます。