Код — это, по сути, способ общения с компьютером. Но компьютеры говорят единицами и нулями, а не статьями Medium, поэтому нам нужен какой-то способ перевести то, что мы понимаем, на то, что понимает компьютер. Разница между интерпретируемым и компилируемым языками заключается в том, как они преодолевают этот разрыв между языком человека и компьютера.

"Что заставляет R Shiny чувствовать себя настолько диссонансом даже для опытных R-программистов, так это то, что R — это интерпретируемый язык, но R Shiny больше похож на компилируемый язык".

Мы можем представить себе работу на интерпретирующем языке, как если бы у нас был собственный личный переводчик. В наших разговорах с компьютером переводчик повторяет то, что мы говорим, предложение за предложением на языке, понятном компьютеру. Интерпретатор может читать наш код построчно. Если бы я хотел, чтобы компьютер напечатал «Hello, World!» Мне просто нужно нажать «выполнить», чтобы интерпретатор перевел все на компьютер, и компьютер вернул первые слова каждого программиста.

Здесь важно помнить, что строка за строкой. Интерпретаторы позволяют вам запускать ваш код по мере его выполнения, небольшими порциями, чтобы отслеживать все, что происходит в вашей программе по мере ее выполнения. Такие языки, как R и Python, работают таким образом, где мы можем запустить некоторый код, проверить некоторые переменные, запустить еще немного кода и так далее.

В то время как интерпретирующие языки подобны личному переводчику, скомпилированные языки подобны личному издателю. Издателям нужна вся книга, прежде чем переводить ее на другой язык и отправлять новой аудитории. Компилируемые языки используют компилятор для «публикации» нашего кода в исполняемый файл (файл .exe), который компьютер читает как книгу. Возьмите классический «Hello, World!» пример. Мы пишем код, а затем компилируем весь скрипт в исполняемый файл. Затем, чтобы увидеть эти два волшебных слова, мы просто запускаем только что созданный исполняемый файл.

Важно то, что мы не можем редактировать код внутри исполняемого файла! Если мы хотим изменить наш код, нам нужно изменить исходный скрипт, перекомпилировать его и запустить новый исполняемый файл. . При работе с компилируемыми языками, такими как C, мы пишем код, компилируем его, извлекаем исполняемый файл, затем редактируем код, перекомпилируем его и извлекаем новый исполняемый файл.

Что заставляет R Shiny чувствовать себя настолько диссонансным даже для опытных R-программистов, так это то, что R является интерпретируемым языком, но R Shiny работает больше как компилируемый язык.

Чтобы глубже понять, что значит для интерпретируемого языка вести себя как скомпилированный язык, давайте рассмотрим быстрый пример приложения Shiny, которое печатает «Hello, World!»

ui <- fluidPage(
  print("Hello, World!")
)

server <- function(input, output, session) {
  # empty for this example
}

# Call the ui and the server function to run the Shiny App
shinyApp(ui, server)

Каждое приложение Shiny состоит из пользовательского интерфейса (пользовательского интерфейса) и сервера. Пользовательский интерфейс описывает то, что видит пользователь, в то время как сервер обрабатывает все (внутренние) расчеты, куда идут все биты науки о данных. Приведенный выше код создает базовую страницу:

Строка shinyApp(ui, server) внизу «компилирует» пользовательский интерфейс и серверную функцию, а затем «публикует» исполняемый файл, который выдает наше «Hello, World!» веб-страница. Обратите внимание, что вы не можете редактировать текст в приложении. Shiny Apps работают как обычная веб-страница, на которой нельзя ничего изменить, можно только выделить текст. Это поведение скомпилированного языка во время игры. Если мы хотим изменить наше приложение, чтобы оно говорило «Привет, Галактика!» нам нужно закрыть «Hello, World!» версии, измените исходный код, а затем повторно «скомпилируйте» наше приложение.

ui <- fluidPage(
  print("Hello, Galaxy!") # Changed greeting to the Galaxy
)

server <- function(input, output, session) {
  # empty for this example
}

# Call the ui and the server function to run the Shiny App
shinyApp(ui, server)

Это тонкое изменение в рабочем процессе R оказывает большое влияние на то, как мы взаимодействуем с нашими программами. Далее рассмотрим пример приложения, которое складывает два числа и выводит их сумму. В типичном R-скрипте программа выглядит так:

number1 <- 10
number2 <- 20

sum_of_numbers <- number1 + number2

print(sum_of_numbers)

Рассмотрим, как переменные number1 , number2 и sum_of_numbers являются глобальными переменными. Когда мы запускаем каждую строку, интерпретатор добавляет переменные в глобальную среду, к которой мы можем получить доступ в консоли и просмотреть в IDE RStudio.

Блестящая версия нашей программы добавления номеров использует преимущества как пользовательского интерфейса, так и функции сервера. Вот один из способов написать наше приложение:

ui <- fluidPage(
  # verbatimTextOutput = print() Show how it would in the console
  verbatimTextOutput("sum_of_numbers")
  # creates a variable "sum_of_numbers" as an output
  # accessed via output$sum_of_numbers
)

server <- function(input, output, session) {
  number1 <- 10
  number2 <- 20

  sum_of_numbers <- number1 + number2

  output$sum_of_numbers <- renderPrint(sum_of_numbers)
  # can be read as:
  # for the sum_of_numbers output, print(sum_of_numbers)

  # renderPrint in the server is paired with verbatimTextOutput in the ui
}

# Call the ui and the server function to run the Shiny App
shinyApp(ui, server)

Теперь здесь происходит нечто большее, поскольку наше приложение должно выполнять вычисления на сервере. Давайте сломаем это!

Переменная ui объявляет вывод с именем sum_of_numbers, который показывает консольный вывод переменной, как если бы мы вызывали print(sum_of_numbers). Помимо этой причудливой строки вывода, функция сервера довольно занята. Мы определяем фиксированные переменные (number1 <- 10 и number2 <- 20) вместе с вычислением, основанным на этих переменных (sum_of_numbers <- number1 + number2). Классический, интерпретативный R. Мы говорим серверу вывести этот расчет в пользовательский интерфейс, чтобы закрыть функцию сервера. Наконец, вызов shinyApp «компилирует» переменную ui и серверную функцию, чтобы получить это:

Допустим, мы хотим найти сумму различных чисел? Как и «Привет, мир!» Например, нам нужно закрыть приложение, затем отредактировать код и перекомпилировать его, чтобы получить другую сумму. Более того, помимо объявлений переменных в коде, у нас нет возможности увидеть, какие значения содержат наши переменные. Это не похоже на язык интерпретации, где во время работы приложения мы можем получить доступ к переменным в командной строке или просмотреть их на панели глобальной среды RStudio. Как и в компилируемых языках, когда вызывается shinyApp, он запускает исполняемый файл, и мы не можем играть с исполняемым файлом так же, как мы играем с нашими интерпретируемыми R-скриптами.

В этом суть. Мы не можем играть с исполняемыми файлами так же, как мы играем со сценариями интерпретируемого языка. Вот что заставляет R Shiny чувствовать себя таким пугающим. Это совершенно новый способ программирования, мышления, решения проблем!

В будущем я планирую опубликовать больше статей, рассказывающих о том, как мы работаем с этой новой парадигмой в процессе разработки Shiny App, и многое другое! А пока обязательно ознакомьтесь со шпаргалкой Shiny (https://raw.githubusercontent.com/rstudio/cheatsheets/main/shiny.pdf) или текст Mastering Shiny (https://mastering-shiny.org/index.html) для получения дополнительной информации о нюансах Shiny и обо всем, что с ним связано.