[Gauche-devel-jp] #<undef>について

アーカイブの一覧に戻る
Shiro Kawai shiro****@gmail*****
2022年 1月 30日 (日) 17:22:27 JST


Schemeには、「戻り値が未規定である」式があります。else節がないif式で条件が偽の場合 (if #f #t)
とか、出力手続きなど副作用だけに意味がある場合等です。
未規定、つまり決められていないだけなのでどんな値を返しても良いんですが、「普通の値」を返すとうっかりそれに意味を見出してしまったりするので、多くのScheme処理系では「これは戻り値として意味がない値だよ」というのを示す特別な値を返すようにしています。Gaucheではそれが
#<undef> です。マニュアル:
https://practical-scheme.net/gauche/man/?l=jp&p=undefined
なおCommon Lispではこういう、意味がない値を返す時はnilにするのが慣習になっています。

#<undef> はへんてこりんな表記ですが、単に「意味がないよ」ということを示しているだけで、れっきとしたSchemeの値です。

 (map (lambda (x) (if (odd? x) x)) '(1 2 3 4 5 6))
  => (1 #<undef> 3 #<undef> 5 #<undef>)

となるのは、xが偶数の場合に (if (odd? x) x) の値が #<undef> になるからです。

(for-each ...)  も副作用のみに意味があるので、for-each自体の戻り値は #<undef> になります。

Land of Lisp の例では、 graph->dot は nodes->dot
の戻り値を使っていません。単に上から順番に実行しているだけで、副作用としての出力にnodes->dotの出力が混ざっているというだけです。graph->dot自身はnodes->dotが何を出力しているかを関知しません。

それから、三平方の例はlist-ecの使い方が違います。
  (list-ec <qualifier> ... <expr>)
のように、一つ以上の<qualifier>の並びの最後に普通の式<expr>がきて、<expr>の値がリストの各要素になります。
<qualifier>には、 (: a 1 n) のような値生成や、 (if <condition>) のようなフィルタがあります。このif
はSchemeのif式ではなく、list-ecが独自に解釈する形式であることに注意してください。

別所さんのコードでは、list-ecの最後のフォームが

  (if (= ...) (list a b c))

になってしまっています
(これは本来はエラーにすべきなんですが、srfi-42の実装がサボっています)。その後に値を生成すべき式が無いので、仕方なく未定義値#<undef>を値としたため、要素が全部#<undef>になってしまいました。

正しい書き方は次のとおりです。インデントを揃えて見てください。(list a b c)が (: ...)や(if ...)と同じレベルにあるでしょう?

        (list-ec (: a 1 n)
                 (: b (+ a 1) n)
                 (: c (+ b 1) n)
                 (if (= (+ (expt a 2) (expt b 2))
                        (expt c 2)))
                 (list a b c))))

--shiro







On Sat, Jan 29, 2022 at 10:00 PM 別所秀一 <bes2h****@gmail*****> wrote:

> はじめまして。GaucheやCommonLispを最近学び始めた別所と申します。
> 仕事はプログラミングとは無関係で、去年からCやPython入門書を読みはじめた初心者です。
>
> いま、オライリーの「プログラミングGauche」」Land of Lisp」を並行して読んでいるところです。(どちらもまだ半分くらいです)
>
>
>  Lispでは必要に応じて小さな関数をつくり、その出力を別の関数に与えたり、別の関数から呼び出してもらったりしながら問題を解決するんだなあ、と感じています。
>
> で、その出力によく#<undef>がまじっていてエラーになります。
>
> たとえば
> gosh> (map (lambda (x) (if (odd? x) x)) '(1 2 3 4 5 6))
> (1 #<undef> 3 #<undef> 5 #<undef>)
>
> if で偽のときに#<undef>がやってくる?
> (filter odd? '(1 2 3 4 5 6)) なら欲しかった(1 3 5)になります。
>
> print すればいいのか
> (for-each (lambda (x) (if (odd? x) (print x))) '(1 2 3 4 5 6)))
> とすると、
> 1
> 3
> 5
> #<undef>
> となり、別の関数でこの出力を受けて、それぞれ2倍するみたいにやるとundefでエラーになります。
> この場合はprintの評価値?
>
> たとえば「Land of
> lisp」P111あたりの7章「グラフをつくる」ではnodes->dotのプリント出力をgraph->dotが受けてさらに加工して次の工程に送っています。
> (defun nodes->dot (nodes)
>   (mapc (lambda (node)
>           (fresh-line)
>           (princ (dot-name (car node)))
>           (princ "[label=\"")
>           (princ (dot-label node))
>           (princ "\"];"))
>         nodes))
>
> (defun graph->dot (nodes edges)
>   (princ "digraph{")
>    1行省略
>   (nodes->dot nodes)
>   (princ "}"))
>
> 関数どうしをうまく組み合わせるためには、この#<undef>たちをどう扱うのがよいのでしょうか。よろしくお願いします。
>
> それから、関数の連携とはちがいますが、
> (define (三平方 n)
>   (list-ec (: a 1 n)
>    (: b (+ a 1) n)
>    (: c (+ b 1) n)
>    (if (= (+ (expt a 2) (expt b 2))
>   (expt c 2))
>        (list a b c))))
> これを実行してみると、
> gosh> (三平方 20)
> (#<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef> #<undef>
>  #<undef> #<undef> ....)
> こんなことになって、結果が確認できません。
>
> 以上、#<undef>での困りごとでした。
>
> _______________________________________________
> Gauche-devel-jp mailing list
> Gauch****@lists*****
> https://lists.osdn.me/mailman/listinfo/gauche-devel-jp
-------------- next part --------------
HTMLの添付ファイルを保管しました...
URL: <https://lists.osdn.me/mailman/archives/gauche-devel-jp/attachments/20220129/509d7e07/attachment-0001.html>


Gauche-devel-jp メーリングリストの案内
アーカイブの一覧に戻る