[NB: продолжение этого репо с использованием GPT-4 можно найти здесь.]
Большие языковые модели (LLM), такие как CHATGPT и Claude, продемонстрировали впечатляющие способности программирования и способны решать проблемы на широком спектре языков и их таксономий. Несмотря на эти успехи, некоторый скептицизм сохраняется из -за того, что эти модели демонстрируют какую -либо основную оценку синтаксических и эксплуатационных правил, лежащих в основе этих языков ( по сравнению с запоминанием моделей учебных данных).
В этом оперативном репозитории, способности программирования CATGPT исследуются с использованием произвольного языка, специфичного для домена (DSL). DSL представляют собой привлекательный субстрат для изучения возможностей вывода LLM, потому что они являются новыми и с меньшей вероятностью были широко встречаются и запоминаются во время обучения 1 . Таким образом, они обеспечивают более прямую проверку того, в какой степени LLM могут сделать вывод правил новых языков программирования несколькими выстрелами .
Здесь, специфичный для домена языка SIL (язык интеграции симметрии) был выбран по двум причинам. Во-первых, крайне маловероятно, что CHATGPT подвергся воздействию любого кода SIL во время обучения, так как это внутренний DSL, разработанный в техническом хедж-фонде под названием Symmetry Investments. Во -вторых, как язык программирования, он имеет некоторые интересные особенности для воспроизведения модели (например, это функциональный язык, который подчеркивает выразительность, но не хватает let , как в Haskell или Ocaml).

После некоторого примера подсказки кода CHATGPT пытается написать код в новом функциональном DSL, известном как «SIL».
Ниже приведена набор подсказок, состоящих из коротких примеров кода SIL, которые подчеркивают его функциональность. После того, как я побудил CHATGPT с задачей и предоставление образцов кода SIL (см. Рисунок ниже; приведенные в этом репо -примере также есть примеры CODE и код SIL), я попросил его выполнить ряд основных задач программирования в SIL.
В приведенных ниже разделах я показываю некоторые из примеров сценариев кода SIL, с помощью которых была вызвана модель (полный набор примеров можно найти здесь) и ее попытки реализовать различные проблемы в 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 операторы, включающие в пример кода SIL, с помощью которого я вызвал модель, синтаксис в этом сгенерированном коде неверен. Во-вторых, Chatgpt Hallucinates (или предполагает) наличие модуля, называемого 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 -более популярный алгоритм соседей в SIL. Это на самом деле является результатом двух подсказок (как описано в сгенерированном кодовом блоке ниже), поскольку модель галлюцинирует/предполагает модуль, называемый distances в первой попытке. Во второй попытке я побудил его реализовать алгоритм, не предполагая существования этого модуля.
Производительность Chatgpt здесь смешана. Во -первых, в некоторых случаях он игнорирует функциональные аспекты SIL (например, внедрение for цикла в первой попытке. В других частях реализации, однако, он ценит, что SIL функционален и точно использует |> и операторы map . Примечательно, что модель, по -видимому, галлуцинирует let , которые не имеют кода, с помощью которого он был поднят. Это, скорее всего, из -за сочетания функциональности SIL -кода.
// 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. На данный момент, Chatgpt's Repsonses несколько разбил; Ни одно из этих решений не имеет большого сходства ни с функциональностью высокого уровня 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. DSL являются потенциально полезным испытательным примером для изучения вывода против запоминания в LLMS, так как они часто имеют отличительные особенности и с меньшей вероятностью будут широко встречаются во время тренировки (если вообще).
В целом, производительность была смешанной: CHATGPT правильно понял, что этот DSL является функциональным языком программирования (хотя иногда его приходилось повторно нанести из этого), и соответственно реализовать свои решения. Тем не менее, в целом он не смог захватить синтаксические правила этого DSL из пяти примеров, предоставленных сценариев. Дальнейшие исследования (такие как использование других DSL, разработка более формальной метрики для оценки кода, сгенерированного LLM, или количественная оценка динамики обучения модели), сделает интригующее расширение этого репо. Наконец, в отдельном сеансе CHATGPT я предоставил этот метапрограмм, чтобы определить, как модель интерпретировала свой собственный код SIL:

CHATGPT рассматривает свою собственную попытку написать код в языковом SIL, специфичном для домена, и описывает некоторые из его функций.
Существуют доказательства того, что запоминание LLM способствует частоте презентации примера обучения и количеством соответствующих токенов, используемых для привлечения модели. ↩