ChatGPTにコードを書いてもらったら間違ってたけど感心した話


ChatGPT、いろいろなことができて面白いですよね。
Arduinoなどのプログラムを書いてもらうという試みもいろいろされているようですが、私も今回ChatGPTにプログラムを書いてもらってみました。

昨年、PowerAppsのプログラムをちょっと書いてみた話を書きましたが、最近またPowerAppsで少しだけ開発をしました。
このプログラムは、M365のユーザー情報を引っ張り出して、一覧表にするというものです。
ユーザー情報を引くためのAPIがPowerAppsには用意されていて、SearchUserV2()という関数です。

ただ、この関数は制約があり、一度に999人までのユーザーの情報しか出力できません。
一覧表にしたいユーザ数は3000以上なので、999人では不足です。

ところが、関数にskipTokenというパラメータを与えると、関数を繰り返し呼ぶことで、「前回のつづき」を出力させることができそうなのです。

このskipTokenの使い方がネットを検索してもよく分からなかったので、ChatGPTに質問してみました。

I am makeing an application on powerapps platform. Please teach me how to use “skipToken:” of SearchUsersV2 function.
PowerAppsでアプリケーションを作っています。SearchUserV2のskipToken:の使い方を教えて下さい。


ほう、一見正しそうなコードを返してきました。
最初のSearchUsersV2コールの戻り値に含まれる、SkipTokenプロパティの値を、次回のSearchUsersV2コールで使いなさい、ということですね。
ちなみにSet(var, value)はグローバル変数varを作成し、そこへvalueを代入する関数です。

SkipTokenのコンセプトはこのコードの通りです。しかし、実は戻り値にはSkipTokenというプロパティは無いんです。戻り値にあるプロパティは「value」「’@odata.nextlink’」の二つです。

I think “First(colUsers).SkipToken” shoud be “First(colUsers).’@odata.nextlink'”, right?
“First(colUsers).SkipToken”ではなく”First(colUsers).’@odata.nextlink'”ではないでしょうか。


あと、SearchUsersV2へのパラメータの与え方が違っています。複数の検索条件パラメータは{keyword1: parameter1, keyword2: parameter2,…}という形で与えなければなりません。
And also, ‘SearchUserV2(“”,{‘ should be ‘SearchUserV2({searchTerm:”,’

だいぶそれっぽいコードになってきましたね。
しかし、ここまでなら実は検索エンジンで簡単に調べられるのです。ここからが本番です。
But it seems that “colUsers” always holds only the last 50 search results, right?
でもこれだと、colUsersには常に最後の50個の検索結果しか入らないのではないですか?


やや曖昧な質問でしたが、「すべての検索結果がほしい」という意図を汲んだコードを出してきました。

ほうほう、これは正しそうですね! Whileなんて関数あったんだ、知らなかったな~



PowerAppsにそんな関数はありません。あなたいい加減なこと言ってませんか?
Hmm, I believe PowerApps doesn’t have “While”.
PowerAppsにはWhileは無いと思います。


ForAll関数に変えた案を出してきました。
ForAll(テーブル、式)はテーブルの各行に式を適用した結果を返す関数です。
テーブルが疑似コード風に {0,1,2,3,4,…} となっているところには目をつぶりましょうか。Sequence()関数を使えているとより良かったですね。

ここでのポイントは、式がIfになっていて、skipTokenが空ならBreak()でForAllから抜けられるところですね!
問題は、PowerAppsにはBreak()なんていう関数はないということです。

というかそもそも、ForAllを中断する方法は提供されていません。
そこを指摘すると・・・
I’m afraid that PowerApps doesn’t provide “Break()”.


またWhile()を出してきました。Whileは無いってさっき言ったやん。
I said PowerApps doesn’t have “While”.

ExitForAllという手段を考案してきました。
えっ、そんなのあったんだ、すごい! と思ってマニュアルを調べてみましたが、そんなものはありません・・・。

それよりも、先刻からForAllの内側でSet関数で変数の値を更新していますが、これ許されないんですよね。
ForAllはループではなく、式は並列に評価されるからです。
There is no means to exit from ForAll. Also, using “Set” inside ForAll loop is prohibited.
ForAllから脱出する方法はありません。あとForAllの中でSetは使えません。


指摘したところは素直に修正して来ました。
ですが・・・skipTokenの値を更新するコードが無いですね。これ動作するんでしょうか?
そもそも、ForAllってループじゃないので、順序的な動作をさせるskipTokenとは相性が悪い感じがします。
It seems that skipToken is not updated in the ForAll loop. Does this works correctly?
skipTokenの値がForAllの中では更新されないようですが、これで正しく動作するんでしょうか。


またWhile出してきました。
3度目です。
No, you can’t use “While.” It is not available on PowerApps.


またExitForAll出してきました。
降参だそうです。

しかし、この一連のやり取りを振り返ってみると「こんな風に書けるんじゃないのかな」という発想自体はとても自然なのが印象的でした。
プログラミング自体はできるけどPowerAppsは良く知らない、という人と話しているような感じです。

つまり、「プログラミングを理解している人」だという感じがするんですね。
正解にはたどり着けなかったとはいえ、少なくとも「それっぽいこと」をできている感じです。
正直、そういう意味ではそこらへんの「普通の人間」より「よっぽど優秀」な感じがして、感慨深いものがあります。

***

なお、今回の課題自体は結局自分でさらにあれこれ調べて解決しました。

上のほうで書いた’@odata.nextlink’はHTTPのGETでパラメータを送るとき同様の”&varName=string&…”という形式の文字列で、この文字列から”skipToken=XXXXX”となっている個所を検索し、XXXXXの部分を取り出してSearchUserV2のskipToken:パラメータに与えることになります。
SearchUserV2を繰り返し呼ぶためにForAllは使えないので、SearchUserV2を;で区切って必要な数だけ繰り返します。
コードとしてはこんな感じです。


Clear(allUsers)
With(Office365ユーザー.SearchUsersV2({top:4000, isSearchTermRequired:false}),
    Set(lastToken, ThisRecord.'@odata.nextlink');
    Collect(allUsers, ThisRecord.value)
);
With(Office365ユーザー.SearchUsersV2({skipToken:Mid(lastToken, Find("skipToken=", lastToken) + 10), top:4000, isSearchTermRequired:false}),
    Set(lastToken, ThisRecord.'@odata.nextlink');
    Collect(allUsers, ThisRecord.value)
);
(以下、必要なだけ上記With文を繰り返す。今回は4000レコード検索なので、あと2回)

Mid(lastToken, Find("skipToken=", lastToken) + 10)の「+10」は”skipToken=”の文字数(10文字)です。このMid関数は「skipToken=」の直後から末尾までの文字列を得るという処理をしています。

コメント