読んでいて補足したくなったところ

linkに替わるものとしてmonitorがある。
プロセス(Pid1)が別のプロセス(Pid2)を監視するときには、
組み込み関数(Built in function:BIF)のerlang:monitorを使う。
この関数は、一意なリファレンスRefを返す。

Ref = erlang:monitor(process, Pid2).

プロセスPid2が終了した場合、'DOWN'というメッセージのtupleがPid1に送られる。
終了した理由は、Reasonという変数に設定されている。

{'DOWN', Ref, process, Pid2, Reason}

もし、Pid2がもともと存在しないプロセスのIDだった場合には、
erlang:monitorを実行した直後に、noprocという理由で'DOWN'のメッセージのtupleが送信される。

linkと異なり、monitorは一方向にしかメッセージが送信されない。

何回もerlang:monitor(process, Pid)を実行すると、プロセスPidがダウンすると、
モニタの数だけ'DOWN'のメッセージが送信される。

設定されたモニタを解除するには、erlang:demonitor(Ref) を呼べばよい。

名前で登録されたプロセスに対してモニタを設定することはできる。
他のノードにあるプロセスについても同様にモニタを設定することができる。

で、ちょっとサンプルコード(コンパイルしてからerlのコマンドラインでmonitorsample:start().を実行)を書いてみると、こんな感じか?(テストしてません)

 -module(monitorsample).
 -export([start/0]).

start() ->
    Pid = spawn (fun() -> wait10sec() end),
    Ref = monitor(process, Pid),
    mon(Ref, Pid).

wait10sec() ->
    receive
        _Any ->
           wait10sec()
    after 10000 ->
        true
    end.

mon(Ref, Pid) ->
  receive
    {'DOWN', Ref, process, Pid, noproc} ->
        io:format("No process exists ~p~n",[Pid]);
    {'DOWN', Ref, process, Pid, Reason} ->
        io:format("process ~p is down by ~p~n",[Pid, Reason]);
    {cancel} ->
        demonitor(Ref);
    _Any -> 
        mon(Ref, Pid)
  end.

catch、try-catchまでは必要ないし、Pid1, Pid2双方のプロセスで対称的なコードでもない。
ちなみに、上記の例で、"No prosess exists"になるのは、よほど負荷が高い(swapでスラッシングとか)場合だろうな。