[NB: يمكن العثور على متابعة لهذا الريبو باستخدام GPT-4 هنا.]
أظهرت نماذج اللغة الكبيرة (LLMS) مثل ChatGPT و كلود قدرات برمجة مثيرة للإعجاب ، وهي قادرة على حل المشكلات عبر مجموعة واسعة من اللغات وتصنيفاتها. على الرغم من هذه النجاحات ، لا يزال بعض الشكوك على مدى ظهور هذه النماذج أي تقدير أساسي للقواعد النحوية والتشغيلية الكامنة وراء هذه اللغات ( مقابل حفظ الأنماط من بيانات التدريب).
في مستودع الهندسة الفوري هذا ، يتم استكشاف قدرات البرمجة الخاصة بـ ChatGPT باستخدام لغة خاصة بالمجال التعسفي (DSL). تمثل DSLs الركيزة الجذابة لدراسة إمكانيات الاستدلال لـ LLMs لأنها جديدة وأقل عرضة للمواجهة على نطاق واسع وحفظها أثناء التدريب 1 . على هذا النحو ، فإنها تتيح اختبارًا مباشرًا للمدى الذي يمكن لـ LLMs استنتاج قواعد لغات البرمجة الجديدة بطريقة قليلة .
هنا ، تم اختيار اللغة الخاصة باللغة الخاصة بالمجال (لغة تكامل التناظر) لسببين. أولاً ، من غير المرجح أن تعرض ChatGPT لأي رمز SIL أثناء التدريب ، لأنه DSL في المنزل تم تطويره بواسطة صندوق تحوط ثقيل للتكنولوجيا يسمى Symmetry Investments. ثانياً ، كلغة برمجة ، لديها بعض الميزات المثيرة للاهتمام للنموذج لإعادة إنتاجها (على سبيل المثال هي لغة وظيفية تؤكد على التعبير ، ولكنها تفتقر إلى let بالتعبيرات كما في هاسكل أو OCAML).

بعد بعض الأمثلة ، يطالب رمز ChatGPT بكتابة الكود في رواية DSL الوظيفية المعروفة باسم "SIL".
فيما يلي مجموعة من المطالبات التي تتكون من أمثلة قصيرة من كود SIL والتي تسلط الضوء على وظائفها. بعد مطالبة ChatGPT بالمهمة وتوفير عينات رمز SIL (انظر الشكل أدناه ؛ أمثلة تاريخية كاملة ورمز SIL في هذا الريبو) ، طلبت ذلك لتنفيذ عدد من مهام البرمجة الرئيسية في SIL.
في الأقسام أدناه ، أُظهر بعضًا من نصوص SILE SILE SILL التي تمت مطالبتها بها (يمكن العثور على مجموعة كاملة من الأمثلة هنا) ومحاولاته لتنفيذ العديد من المشكلات في SIL.
الموجه الأول هو برنامج نصي للتعامل مع بعض وظائف خادم البريد. على هذا النحو ، فإنه يختلف اختلافًا كبيرًا عن نوع المشكلة التي سأطرحها لاحقًا على ChatGPT لحلها ، لكنها توضح بعضًا من بناء الجملة وهياكل البيانات والجوانب الوظيفية لـ SIL (على سبيل المثال |> ).
// example of using IMAP IDLE to run rules on new mail
import imap
moveMessages(session,ids,target) => if (ids.length > 0 ) then imap.moveUIDs(session,ids,target) else false
login = imap.ImapLogin(environment( " IMAP_USER " ),environment( " IMAP_PASS " ))
server = imap.ImapServer( " imap.fastmail.com " , " 993 " )
session = imap.Session(server,login, true ,imap.Options(debugMode: true )) | > imap.openConnection | > imap.login
rules=[ [
[ " INBOX/0receipts " ,
[
" FROM [email protected] " ,
" FROM interactivebrokers.com " ,
]],
[ " Junk " ,
[
" FROM Tapatalk " ,
]],
[ " INBOX/newsletters " ,
[
" FROM [email protected] " , " HEADER X-mailer mailgun " , " HEADER X-mailer WPMailSMTP/Mailer/mailgun 2.4.0 " , " HEADER X-mailer nlserver " ,
" FROM hbr.org " , " FROM elliottwave.com " , " OR FROM cio.com FROM cio.co.uk " , " FROM substack.com " , " FROM eaglealpha.com " ,
" FROM haaretz.com " , " FROM gavekal.com " , " FROM go.weka.io " , " FROM marketing.weka.io " , ` HEADER list-unsubscribe "" ` ,
` HEADER list-Id "" ` , ` HEADER list-Post "" ` , ` HEADER list-owner"" ` , ` HEADER Precedence bulk ` , ` HEADER Precedence list ` ,
` HEADER list-bounces "" ` , ` HEADER list-help "" ` , ` HEADER List-Unsubscribe "" ` , " FROM no-reply " ,
]],
[ " INBOX/notifications " ,
[
` KEYWORD "$IsNotification" ` , " FROM [email protected] " , " FROM [email protected] " , " FROM skillcast.com " ,
" FROM reedmac.co.uk " , " FROM [email protected] " , " FROM [email protected] " , " FROM [email protected] " ,
]],
]
runRules(Session,Rules) => Rules
| > map(target => [target[ 0 ],(target[ 1 ] | > map(term => imap.search(Session,term).ids))])
| > mapa(set => moveMessages(Session,set[ 1 ] | > join,set[ 0 ]))
runRulesBox(Session,Rules,Mailbox) => {
imap.select(Session,Mailbox)
in runRules (Session,Rules)
}
inboxes=[ " INBOX " ]
result = inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
print(result)
import parallel;
threadFunction(x) => {
imap.idle(session)
in inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
}
parallel.runEvents((x) => false ,[threadFunction]) يهدف مثال رمز المثال الثاني بالمثل إلى تسليط الضوء على بعض ميزات DSL لهذا النموذج ، ويقدم بعض وظائف المكتبة القياسية الجديدة مثل iota و fold .
import imap
import imap_config
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// -------------------------------------------------------------------------------------------------
// Some helper functions.
//
// Firstly, a function to join an array of strings.
joinFields(flds, sep) => {
len(flds) > 0 | > enforce( " Cannot join an empty array. " )
in fold (flds[ 1 :$], (str, fld) => str ~ sep ~ fld, flds[ 0 ])
}
// Secondly, a field formatter which strips the field prefix and pads to a fixed width.
// E.g., ("From: [email protected]" |> fmtField(20)) == "[email protected] "
fmtField(field, width) => {
pad(str) => iota(width - len(str)) | > fold((a, i) => a ~ " " , str)
in field
| > string .split( " : " )[ 1 :$]
| > joinFields( " : " )
| > pad
}
// And thirdly, a function which concatenates the headers into a formatted string.
fmtHeaders(outStr, headers) => {
outStr ~ " " ~ joinFields(headers, " | " ) ~ " n "
}
// -------------------------------------------------------------------------------------------------
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " INBOX " )
// Get the number of messages in the inbox.
msgCount = imap.status(session, inbox).messages
// Select the default inbox.
inbox | > imap.examine(session, _)
// Get the headers (date, from and subject) for each message, from oldest to newest, format and
// print them.
headers =
iota(msgCount)
| > map(id => " # " ~ toString(id + 1 ))
| > map(id =>
imap.fetchFields(session, id, " date from subject " ).lines
| > map(hdr => fmtField(hdr, 40 )))
| > fold(fmtHeaders, " INBOX: n " )
print(headers)توضح عينة الكود الثالث أيضًا بعض الميزات غير العادية لهذا DSL ، بهدف أن يستخدم ChatGPT هذه في تطبيقاتها التالية.
// This script will search for emails and match new issue numbers with resolutions to report the
// number of outstanding alerts.
import imap
import * from imap.query
import imap_config
import dates
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " support " )
// Select the default inbox.
inbox | > imap.examine(session, _)
// These criteria are common for both our searches.
commonCrit = imap.Query()
| > and(from( ` [email protected] ` ))
| > and(sentSince(dates. Date ( 2020 , 5 , 13 )))
// Get each of the alerts and resolutions from the past week (13-19 May 2020).
alertMsgIds =
imap.search(session, imap.Query(subject( " Alert: new issue " )) | > and(commonCrit)).ids
resolutionMsgIds =
imap.search(session, imap.Query(subject( " Resolution: issue " )) | > and(commonCrit)).ids
// A function to get the alert ID from a message subject.
getAlertId(msgId) => {
imap.fetchFields(session, toString (msgId), " subject " ).lines[ 0 ]
| > string .split()[$ - 1 ]
}
// A function to remove an entry from a table whether it's there or not.
removeIfExists(tbl, key) => {
if find( keys (tbl), key) == [] then
tbl
else
removeEntry(tbl, key)
}
// Now find those alerts which have no resolution. Firstly the subject for each alert, get the
// issue number end and store it in a table.
allAlertTable = alertMsgIds | > fold((tbl, msgId) => addEntry(tbl, getAlertId(msgId), msgId), {})
// Go through the resolutions and remove their corresponding alerts from the table.
unresolvedAlertTable =
resolutionMsgIds | > fold((tbl, msgId) => removeIfExists(tbl, getAlertId(msgId)), allAlertTable)
// Create a report with the date of the unresolved alerts.
report =
keys (unresolvedAlertTable)
| > map(alertId => {
msgId = unresolvedAlertTable[alertId] | > toString
in [ alertId
, imap.fetchFields(session, msgId, " date " ).lines[ 0 ]
, imap.fetchText(session, msgId).lines[ 0 ]
]
})
| > fold((outStr, tuple) => {
outStr ~ " Issue: " ~ tuple[ 0 ] ~ " n " ~ tuple[ 1 ] ~ " n Summary: " ~ tuple[ 2 ] ~ " n "
}, " n UNRESOLVED ISSUES FROM THE PAST 10 DAYS: nn " )
// Close the session.
imap.closeConnection(session)
// Print the report last.
print(report) كتمرين أولي ، طلبت من النموذج تنفيذ قاعدة بيانات علائقية بسيطة للغاية في SIL ، مع الوظائف الأساسية مثل مقارنة وطباعة الفرق بين بنية البيانات (لاحظ أن // يدل على التعليق في SIL).
// Here, ChatGPT was prompted to write a a very simple, schematic relational database in SIL
// This prompt proved too general, perhaps, and after requesting further information, I prompted the model to generate a simple, schematic database with functionalities such as "compare" and "diff" for two or more tables
users = [ { " id " : 1 , " name " : " John Doe " , " email " : " [email protected] " }, { " id " : 2 , " name " : " Jane Smith " , " email " : " [email protected] " }, { " id " : 3 , " name " : " Bob Johnson " , " email " : " [email protected] " },]
orders = [ { " id " : 1 , " user_id " : 1 , " product " : " Widget " , " quantity " : 2 , " price " : 19.99 }, { " id " : 2 , " user_id " : 2 , " product " : " Gadget " , " quantity " : 1 , " price " : 29.99 }, { " id " : 3 , " user_id " : 3 , " product " : " Thingamajig " , " quantity " : 3 , " price " : 39.99 },]
// Compare two tables
compareTables(table1, table2) => {
table1 == table2
}
// Diff two tables
diffTables(table1, table2) => {
table1.filter(i => ! table2.includes(i))
}
print(compareTables(users, users)) // true
print(diffTables(users, orders)) // [{"id": 1, "name": "John Doe", "email": "[email protected]"}]تطبيق خوارزميات الفرز هو سؤال مقابلة هندسة البرمجيات النموذجية. هنا ، طلبت من ChatGPT تنفيذ Bubblesort (من الناحية النظرية خوارزمية الفرز الأساسية) في SIL. فيما يلي الرد:
bubbleSort(arr) => {
for i in 1 ... len(arr) {
for j in 1 ... len(arr) - i {
if (arr[j] > arr[j + 1 ]) {
temp = arr[j]
arr[j] = arr[j + 1 ]
arr[j + 1 ] = temp
}
}
}
arr
}
arr = [ 4 , 6 , 1 , 3 , 5 , 2 ]
print(bubbleSort(arr)) على الرغم من أن هذا البرنامج النصي ، في الواقع ، هو تطبيق عمل لـ Bubblesort ، فإن النموذج يتجاهل على نطاق واسع الجوانب الوظيفية لـ SIL. على سبيل المثال ، هذا تنفيذ Bubblesort for الحلقات بدلاً من العودة.
بعد ذلك ، دفعت النموذج إلى كتابة نص لحساب متوسط القائمة (استجابة تم إنشاؤها أدناه). كان هذا ، ربما ، أحد أقل الردود مرضية. أولاً ، على الرغم من أن عبارات if/else التي تظهر في رمز SILE على سبيل المثال الذي دفعت إليه النموذج ، فإن بناء الجملة في هذا الرمز الذي تم إنشاؤه غير صحيح. ثانياً ، يلموس شاتغبت (أو يفترض) وجود وحدة تسمى math ودالة sort (هذه هي افتراضات معقولة ، ولكنها تقلل بشكل كبير من تعقيد المشكلة المطلوبة).
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
import math
// Function to compute the median of a list of integers
median(numbers) => {
// Sort the list of numbers
sortedNumbers = sort(numbers)
// Get the middle index of the sorted list
middleIndex = math.floor(len(sortedNumbers) / 2 )
// If the list has an odd number of elements, return the middle element
if len(sortedNumbers) % 2 == 1 :
return sortedNumbers[middleIndex]
// Otherwise, return the average of the two middle elements
else :
return (sortedNumbers[middleIndex - 1 ] + sortedNumbers[middleIndex]) / 2
}
تمت مطالبة ChatGPT بعد ذلك بتنفيذ خوارزمية الجيران K -Nearest في SIL. هذا هو في الواقع نتيجة لمطالبات اثنين (كما هو موضح في كتلة التعليمات البرمجية التي تم إنشاؤها أدناه) ، لأن النموذج يهلل/يفترض وحدة تسمى distances في المحاولة الأولى. في المحاولة الثانية ، دفعتها إلى تنفيذ الخوارزمية دون افتراض وجود هذه الوحدة.
أداء ChatGpt هنا مختلط. أولاً ، في بعض الحالات ، يتجاهل الجوانب الوظيفية لـ SIL (مثل تنفيذ حلقة for A في المحاولة الأولى. ومع ذلك ، فإنه في أجزاء أخرى من التنفيذ ، ومع ذلك ، فإنه يقدر أن SIL وظيفية ، وتوظيف |> ومشغلي map بدقة. وخاصةً ، يبدو أن النموذج يسمح let التي لا تسمح بها في الكود على سبيل المثال.
// Note that this is the fusion of two separate scripts generated by ChatGPT to solve the k-nearest neighbours algorithm, as described in the comments below
// Overall, these attempts seem reasonable, but it does appear to hallucinate "let" bindings which do not feature in the example code with which it was prompted. This is likely due to conflating the functionality of SIL code with OCaml or F#
// Attempt 1:
// This is the first ChatGPT attempt when prompted to generate a script for the k-nearest neighbours algorithm
// In this case, it assumes (or hallucinates) a library called "distances"
import distances
// Define a point as a tuple of x and y coordinates
type Point = (num, num)
// Find the distance between two points
distance(p1: Point, p2: Point) => {
let xDistance = p1[ 0 ] - p2[ 0 ]
let yDistance = p1[ 1 ] - p2[ 1 ]
in sqrt (xDistance * xDistance + yDistance * yDistance)
}
// Find the k nearest points to a given point
kNearest(point: Point, points: [Point], k: num) => {
// Compute the distances between the given point and all other points
let distances = points | > map(p => (p, distance(point, p)))
// Sort the points by distance
distances = distances | > sort((d1, d2) => d1[ 1 ] < d2[ 1 ])
// Return the k closest points
in distances[:k] | > map(d => d[ 0 ])
}
// Attempt 2:
// Next, ChatGPT is prompted to generate a script without importing the questionable "distances" library
// Again, it assumes some in-built functions, such as "sort" or "sqrt"
// Function to calculate the distance between two points
distance(p1, p2) => {
sum = 0
for i in 0 .. len(p1) - 1 {
sum = sum + (p1[i] - p2[i]) ^ 2
}
sqrt(sum)
}
// Function to find the k nearest neighbors
k_nearest_neighbors(data, point, k) => {
distances = data | > map(p => (p, distance(p, point)))
distances | > sort((a, b) => a[ 1 ] < b[ 1 ]) | > take(k) | > map(p => p[ 0 ])
}
واحدة من الميزات المثيرة للاهتمام للغات الوظيفية هي أنها يمكن أن تكون معبرة للغاية. هنا ، دفعت ChatGPT إلى تنفيذ map المشغلين الوظيفيين الأساسيين ، filter ، reduce (أو fold في سياق اللغات الوظيفية). في الحالات القليلة الأولى ، يبدو أن النموذج يفقد تتبع الجوانب الوظيفية لـ SIL ، ولكنه يمكن أن يعيد تنفيذ الكود بطريقة أكثر وظيفية عند المطالبة بها.
// map
map(fn, list) => {
result = []
for i in list {
result.append(fn(i))
}
return result
}
// filter
filter(fn, list) => {
result = []
for i in list {
if (fn(i)) {
result.append(i)
}
}
return result
}
// reduce
reduce(fn, list, initial) => {
result = initial
for i in list {
result = fn(result, i)
}
return result
}
// reduce (prompted to use functional operators such as pipe |>, in addition to the 'map' and 'filter' functions defined previously)
reduce(fn, list, initial) =>
list | >
filter(fn, _, initial) =>
map(fn, _, initial) =>
initialProject Euler هي مجموعة من المشكلات الرياضية والبرمجة (والتي أعتقد أنها تجعل مطالبات مثيرة للاهتمام لـ LLMS). هنا ، أطلب من chatgpt لحل أول مشكلتين للمشروع euler باستخدام SIL. في هذه المرحلة ، قام RestGpt's Repsonsess بعمليات Datgpt إلى حد ما ؛ لا يشبه أي من هذه الحلول الكثير من الوظائف عالية المستوى لـ SIL أو بناء جملة Exaxct. قد يكون من المثير للاهتمام توفير المزيد من أمثلة رمز SIL في هذه المرحلة ثم إعادة توزيع النموذج لحل هذه المشكلات.
// Project Euler problem #1:
// Here, my prompt was to solve the (easy) first problem of the Project Euler series (https://projecteuler.net/problem=1)
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
for i in 1 ... 1000 {
if (i % 3 == 0 || i % 5 == 0 ) {
result += i
}
}
print(result) // Project Euler problem #2:
// This prompt is to solve the second Project Euler problem (https://projecteuler.net/problem=2)
// The solution proposed by ChatGPT is sensible, but potentially inefficient, and ignores the recursion of functional languages
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
fib(n) => {
if (n <= 1 ) {
return n
}
return fib (n - 1 ) + fib(n - 2 )
}
for i in 1 ... 100 {
val = fib(i)
if (val > 4000000 ) {
break
}
if (val % 2 == 0 ) {
result += val
}
}
print(result)
لا يزال استكشاف قدرة LLMS على استنتاج وفهم ميزات لغة البرمجة الجديدة بطريقة قليلة من الطلقة سؤالًا مفتوحًا ومثيرًا للاهتمام. هنا ، تم استكشاف هذه القدرات في سياق دفع chatgpt لحل المشكلات المطالبة بلغة جديدة خاصة بالمجال (DSL) تسمى SIL. DSLs هي حالة اختبار محتملة محتملة لاستكشاف الاستدلال مقابل الاحتفاظ في LLMS ، حيث أن لديها في كثير من الأحيان ميزات مميزة وأقل عرضة للمواجهة على نطاق واسع أثناء التدريب (إن وجدت).
بشكل عام ، تم خلط الأداء: لقد فهمت ChatGPT بشكل صحيح أن DSL هذه هي لغة برمجة وظيفية (على الرغم من أنه كان لا بد من إعادة عرض هذا) ، وتنفيذ حلولها وفقًا لذلك. ومع ذلك ، فشلت على نطاق واسع في التقاط القواعد النحوية لهذا DSL من النصوص الخمسة على سبيل المثال المقدمة. من شأن إجراء مزيد من التحقيقات (مثل استخدام DSLs الأخرى ، أو تطوير بعض المقياس الأكثر رسمية لتقييم الكود الذي تم إنشاؤه بواسطة LLM ، أو تحديد ديناميات التعلم للنموذج) أن يجعل تمديدًا مثيرًا للاهتمام لهذا الريبو. أخيرًا ، في جلسة ChatGpt منفصلة ، قدمت هذا التعبير الوصفي لتحديد كيفية تفسير النموذج من رمز SIL الخاص به:

تدرس ChatGPT محاولتها الخاصة لكتابة التعليمات البرمجية في اللغة الخاصة بالمجال ، ويصف بعض ميزاتها.
هناك دليل على تعزيز حفل LLM من خلال تواتر عرض مثال التدريب وعدد الرموز ذات الصلة المستخدمة لمطالبة النموذج. ↩