![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?8acaa2e)
CLispを勉強し始めたところです。
リストを受け取ってその最大値を返す関数を作成したく、以下のようなプログラムを作成しました。
(defun l-max (l)
(let ((maxe (car l)))
(loop for x from 0 to (- (length l) 1)
do
(print maxe)
(print (nth x l))
(if (< maxe (nth x l)) (set 'maxe (nth x l)))
)
maxe
)
)
実行例は以下の通りです。
> (l-max '(1 3 2 5))
1
1
1
3
1
2
1
5
1
出力は
1
1
1
3
3
2
3
5
5
となると予想していたのですが、cond内がうまく処理されていないようです。
対処法を教えていただきたいです。よろしくお願いします。
No.1ベストアンサー
- 回答日時:
まず、だな。
> リストを受け取ってその最大値を返す関数を作成
前提としてANSI Common Lispには既にmaxと言う関数がある。
Function MAX, MIN:
https://www.lispworks.com/documentation/HyperSpe …
基本的にANSI Common Lispには「何でもある」って思っていていい(笑)。
ANSI Common Lispはある意味「究極のエンジニアリング言語」を目指して作られてるんで、エンジニアリングツールとして見た場合、ほぼ「完璧な」関数群を備えてる・・・・・・そのため仕様書が電話帳みてぇになってるんだが(笑)。
んでmaxは基本的にはこう使う。
CL-USER> (max 1 3 2 5)
5
maxは可変長引数の関数だから、与えられた引数の中から最大値を返す。
・・・ただ、お題は「リストの要素の」最大値を返せ、って言ってるんだよな。
しかし問題はない。リストの要素の最大値を返したい場合、ANSI Common Lispではこう書けば良い。
CL-USER> (apply #'max '(1 3 2 5))
5
関数applyは第二引数のリストへ第一引数の関数を適用させる。言い換えると、リストの「カッコを外す」。
Function APPLY:
https://www.lispworks.com/documentation/HyperSpe …
#'(シャープクオート)ってのはちと気持ち悪い表現なんだけど、ANSI Common Lispでは変数と関数の名前空間が別々になっていて、これを付けないとmaxは単なる変数だと解釈されちまう。
従って、「これは関数ですよ」と教える為に#'が存在する。
つまり、お題の最短解自体は
(defun l-max (l)
(apply #'max l))
になる、と言う事だ。
まずは「自分で何か書く」際に、ANSI Common Lispビルトイン関数を調べる、と言うクセを付けよう。まぁ何らかは「大体ある」。それらを「パーツとして」利用して関数を組み上げるのが一番ラクで、かつ効率がいい。
取り敢えず、何かあったらCommon Lisp HyperSpecを調べるようにしよう。
Common Lisp HyperSpec:
https://www.lispworks.com/documentation/HyperSpe …
さて、提示コードだけど、問題はsetだ。こりゃあんまり使わん。
Function SET:
https://www.lispworks.com/documentation/HyperSpe …
こう書いてある。
Notes:
The function set is deprecated.
set cannot change the value of a lexical variable.
訳: 関数setは非推奨です。setはレキシカル変数の値は変更出来ません。
「レキシカル変数」が何か、と言うと、提示されたコードではletで束縛された変数、つまりmaxeだ。maxeはsetで変更出来ない、んで提示された出力になってるんだ。
言い換えるとsetを使ってもmaxeは変更出来ないんで、ずーっとmaxeは1のままになっている。
通常、現代のCLerはsetfマクロを使う。
Macro SETF, PSETF:
https://www.lispworks.com/documentation/HyperSpe …
(defun l-max(l)
(let ((maxe (car l)))
(loop for x from 0 to (1- (length l)) ;; 1- と言う名の関数がある
do (print maxe)
(print (nth x l))
(if (< maxe (nth x l)) (setf maxe (nth x l)))) ;; setfにする
maxe))
そうすれば貴方の予想通りの動きになる。
CL-USER> (l-max '(1 3 2 5))
1
1
1
3
3
2
3
5
5
なお、拡張loopの使用方法は少々厄介だ。貴方が書いたコードはちと無駄が多い。
恐らく、拡張loopを使うとしたら、本当に書きたいコードは次のようになるんじゃないか。
(defun l-max(l)
(loop with maxe = (car l) ;; with でローカル変数を設定出来る
for x in l ;; in でリストlから順次要素を引っこ抜いてxに束縛可能
do (print maxe)
(print x)
when (< maxe x) ;; when と言う条件節がloopには用意されている
do (setf maxe x)
finally (return maxe))) ;; finally節で何を返したいか指定可能
拡張loopの愛用者が多いのは事実だけど、ちとCOBOL的な冗長さを感じる事は否めない。
ぶっちゃけ、もっと良いのはreduceを使う事だと思う。
Function REDUCE:
https://www.lispworks.com/documentation/HyperSpe …
(defun l-max(l)
(reduce #'(lambda (x maxe)
(print maxe)
(print x)
(if (< maxe x) x maxe)) l :initial-value (car l)))
これは出力結果は違ってくるが、一方計算自体は正しく行われる。
CL-USER> (l-max '(1 3 2 5))
1
1
3
1
2
3
5
3
5
「出力結果が違う」のは、こっちはmaxeを「破壊的変更をしてない」事に拠る。
setfは「変数の値を書き換える」が、reduceは条件に応じてxとmaxeの値を「すげ替えている」だけで「書き換え」はしてないんだ。よって、条件に一致しない時にはmaxeの値は前回の値を「そのまま持っている」事となる。
いずれにせよ、これが「関数型プログラミング」で、「値を書き換えない」モダンなプログラミングのやり方、だろう。
でも、出力しないのなら、やっぱり最初に提示したapplyとmaxの組み合わせが一番シンプルで「適切な解」なんじゃないか、と思う。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) 順列をランダムに発生するプログラム 1 2022/11/16 12:16
- Visual Basic(VBA) VBAのユーザーフォームのテキストボックスに入力制限をしたい 6 2022/11/15 08:28
- その他(プログラミング・Web制作) 十進BASICでの再帰についての質問です。 2 2022/11/18 09:17
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- その他(プログラミング・Web制作) どうしてもエラーが解決できません。 1 2022/07/23 04:32
- Visual Basic(VBA) vba GetAsyncKeyState関数について 1 2023/08/24 12:08
- PHP PHP ページング データベース 1 2022/06/16 10:30
- その他(プログラミング・Web制作) pythonリストの特定の値を表示htmlで表示できない 2 2022/05/14 05:48
- Visual Basic(VBA) Excel マクロについての相談 5 2024/03/20 15:02
このQ&Aを見た人はこんなQ&Aも見ています
-
性格の違いは生まれた順番で決まる?長男長女・中間子・末っ子・一人っ子の性格の傾向
同じ環境で生まれ育っても、生まれ順で性格は違うものなのだろうか。家庭教育研究家の田宮由美さんに教えてもらった。
-
応用情報技術者試験の令和元年秋、午後のプログラムの問題がわからないです。
C言語・C++・C#
-
分かる人は簡単なのだろうが、vscodeのマルチルートワークスペースで困ってます。
その他(プログラミング・Web制作)
-
0 == False はいいけど
C言語・C++・C#
-
-
4
Webプログラムってネイティブアプリプログラムに比べて遥かに簡単すぎる気がするのですが気の所為ですか
その他(プログラミング・Web制作)
-
5
pythonで複数画像からgifを作る方法
その他(プログラミング・Web制作)
-
6
楽しくて最高のプログラミング言語を作りたいのですが、そもそもプログラミング言語を作る意味なんてないと
その他(プログラミング・Web制作)
-
7
プログラミングについて。 1つのループで Aという計算と Bという計算をするのと これらを分けて2つ
C言語・C++・C#
-
8
右ビットシフト
C言語・C++・C#
-
9
プログラム言語について プログラム言語c c++ java iPhone用言語だけ使ったら性能軽さな
C言語・C++・C#
-
10
Notepad++の関数リスト表示の変更方法をお教えください。
C言語・C++・C#
-
11
C言語をコンパイルするとコンピュータ上でどう動くかというコードになるみたいな説明をよく聞くのですがこ
C言語・C++・C#
-
12
mallocについて
C言語・C++・C#
-
13
プログラミング
その他(プログラミング・Web制作)
-
14
正規表現 URL抽出「 [\\/\\b]{0} 」 の意味教えてください。
その他(プログラミング・Web制作)
-
15
c++でテンプレートのコードでわからないことがあります
C言語・C++・C#
-
16
swift言語の最適化 swift最適化を最大限に出来たらcc++よりもだいぶ早く実行出来ますか?s
C言語・C++・C#
-
17
なんでブラウザでPHPを動かすためだけにOSにPython2(Python3)を入れて、C(GCC)
PHP
-
18
システムエンジニアの適正について
C言語・C++・C#
-
19
プログラミング、アーキテクチャ好きに質問です。 kotlinなどのMVVM、単方向データフローの考え
その他(プログラミング・Web制作)
-
20
Pythonって何を意識した言語なんですか?コマンドライン?
その他(プログラミング・Web制作)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
foreach 回数制限
-
PerlでCabochaを呼び出すには(...
-
Application.ScreenUpdating = ...
-
セレクトメニューで2つの項目...
-
メモリをアドレスを直接指定し...
-
UWSC:ポップアップウインドウ...
-
複数列を持ったリストボックス...
-
16進の10進変換について
-
文字の横にプルダウンを表示さ...
-
formで特定のinputを送信しない...
-
JSONで文字列が長い時
-
[Ruby] irbにおける文字化け
-
シェルスクリプトで、空白(ス...
-
SELECT要素について
-
文字のカラーとフォントの指定...
-
TeraPadでよく使う文字を特定キ...
-
子windowsからsubmit()後にclos...
-
awk の int()に関数について
-
セグメンテーション違反
-
構造体の各データの表示につい...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CLispのloop内の挙動について
-
Perlで自分自身の関数名を知る...
-
Net::Telnetでタイムアウト時間...
-
print <<"_HTML_"の中でサブル...
-
Rubyのgets関数について
-
10進数→2進数
-
Perlで複数の値を返す良い方法...
-
作業域が消える(ように見える)
-
CGI初心者です
-
検索機能の作成で困っています
-
foreach 回数制限
-
Pythonのマルチプロセスでの並...
-
ハノイの塔の問題で困っており...
-
LISPで連想配列の操作?
-
PERLの「!=」と「=~」 or...
-
PerlでCabochaを呼び出すには(...
-
Wコロン
-
シェルでawkを使い行数を取り出...
-
プロトタイプ宣言のワーニング...
-
icmp socket error
おすすめ情報