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も見ています
-
プロが教えるわが家の防犯対策術!
ホームセキュリティのプロが、家庭の防犯対策を真剣に考える 2組のご夫婦へ実際の防犯対策術をご紹介!どうすれば家と家族を守れるのかを教えます!
-
Webプログラムってネイティブアプリプログラムに比べて遥かに簡単すぎる気がするのですが気の所為ですか
その他(プログラミング・Web制作)
-
pythonで複数画像からgifを作る方法
その他(プログラミング・Web制作)
-
楽しくて最高のプログラミング言語を作りたいのですが、そもそもプログラミング言語を作る意味なんてないと
その他(プログラミング・Web制作)
-
-
4
右ビットシフト
C言語・C++・C#
-
5
プログラミングについて。 1つのループで Aという計算と Bという計算をするのと これらを分けて2つ
C言語・C++・C#
-
6
システムエンジニアの適正について
C言語・C++・C#
-
7
なんでブラウザでPHPを動かすためだけにOSにPython2(Python3)を入れて、C(GCC)
PHP
-
8
Pythonって何を意識した言語なんですか?コマンドライン?
その他(プログラミング・Web制作)
-
9
コードを書いて下さい( ; ; )写真有り
HTML・CSS
-
10
Notepad++の関数リスト表示の変更方法をお教えください。
C言語・C++・C#
-
11
C言語 配列と関数の練習問題
C言語・C++・C#
-
12
mallocについて
C言語・C++・C#
-
13
goo は、放置?
HTML・CSS
-
14
プログラミング、アーキテクチャ好きに質問です。 kotlinなどのMVVM、単方向データフローの考え
その他(プログラミング・Web制作)
-
15
プログラマーと学歴の関係性について
その他(プログラミング・Web制作)
-
16
分かる人は簡単なのだろうが、vscodeのマルチルートワークスペースで困ってます。
その他(プログラミング・Web制作)
-
17
C言語をコンパイルするとコンピュータ上でどう動くかというコードになるみたいな説明をよく聞くのですがこ
C言語・C++・C#
-
18
小学1年生の子です。塾に行かせるのは難しいので、自宅で学べたらと思うのですが、子供にプログラミングを
その他(プログラミング・Web制作)
-
19
応用情報技術者試験の令和元年秋、午後のプログラムの問題がわからないです。
C言語・C++・C#
-
20
javaScriptのコードの修正をお願いします。
JavaScript
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CLispのloop内の挙動について
-
Perlで use strict して our変数
-
Application.ScreenUpdating = ...
-
JSONで文字列が長い時
-
メモリをアドレスを直接指定し...
-
実行時エラー 3020の対策
-
16進の10進変換について
-
formで特定のinputを送信しない...
-
シェルスクリプトで、空白(ス...
-
子windowsからsubmit()後にclos...
-
VBAでPDFのコピーとリネームを...
-
全然分からず困っています。習...
-
vscode 文字化け
-
SSI にグローバル変数を渡すこ...
-
ACCESS テキストボックスを隙...
-
セレクトボックスから別窓にジ...
-
select や option のCSS設定
-
構造体の各データの表示につい...
-
【C#】数値の範囲チェックについて
-
pythonで演算子を変数に代入す...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Perlで複数の値を返す良い方法...
-
HASH(0xほげほげ)
-
プロトタイプ宣言のワーニング...
-
Pythonのプログラミングの質問...
-
Net::SSH::Perlについて
-
perlのスクリプトどこが間違っ...
-
print <<"_HTML_"の中でサブル...
-
内部処理形式が日付型 (Date) ...
-
Perlで use strict して our変数
-
変数に値を代入するのに、まずu...
-
Perl:計算誤差について
-
icmp socket error
-
Perlで足し算をするには
-
連想配列とforeach
-
Wコロン
-
PERLの「!=」と「=~」 or...
-
for文の中でのforeachの問題
-
Perlで自分自身の関数名を知る...
-
PerlでCabochaを呼び出すには(...
-
Net::Telnetでタイムアウト時間...
おすすめ情報