Подтвердить что ты не робот

Побочные эффекты в Scala

Я изучаю Scala в наши дни. У меня слабое знакомство с Haskell, хотя я не могу утверждать, что хорошо это знаю.

Паратетическое замечание для тех, кто не знаком с Haskell

Одна черта, которая мне нравится в Haskell, заключается в том, что не только функции являются первоклассными гражданами, но и побочными эффектами (позвольте мне назвать их действия). Действие, которое при выполнении наделяет вас значением типа a, относится к определенному типу IO a. Вы можете передавать эти действия примерно так же, как и любое другое значение, и комбинировать их интересными способами.

Фактически, объединение побочных эффектов - единственный способ в Haskell сделать что-то с ними, так как вы не можете их выполнить. Скорее, программа, которая будет выполнена, представляет собой комбинированное действие, которое возвращается вашей функцией main. Это аккуратный трюк, который позволяет функциям быть чистыми, в то время как ваша программа действительно делает что-то другое, кроме потребляемой мощности.

Основное преимущество этого подхода заключается в том, что компилятор знает части кода, где вы выполняете побочные эффекты, поэтому он может помочь вам поймать ошибки с ними.

Актуальный вопрос

Есть ли какой-нибудь способ в Scala, чтобы у вас были проверки побочных эффектов типа компилятора, так что, например, вы гарантированно не выполняете побочные эффекты внутри определенной функции?

4b9b3361

Ответ 1

Нет, это принципиально невозможно в Scala, поскольку язык не обеспечивает ссылочную прозрачность - языковая семантика не обращает внимания на побочные эффекты. Ваш компилятор не будет отслеживать и обеспечивать свободу от побочных эффектов для вас.

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

Ответ 2

Возможность принудительного применения ссылочной прозрачности в значительной степени несовместима с целью Scala наличия системы класса/объекта, которая совместима с Java.

Java-код может быть нечистым произвольным образом (и может быть недоступен для анализа при запуске компилятора Scala), поэтому компилятору Scala придется предположить, что весь внешний код нечист (присвоение им типа IO). Чтобы реализовать чистый Scala код с вызовами на Java, вам придется обернуть вызовы в чем-то эквивалентном unsafePerformIO. Это добавляет шаблон и делает взаимодействие более менее приятным, но оно ухудшается.

Предположим, что весь код Java находится в IO, если программист promises в противном случае в значительной степени убьет наследование от классов Java. Все унаследованные методы должны приниматься в типе IO; это даже было бы верно для интерфейсов, так как компилятор Scala должен был предположить существование нечистой реализации где-то там на Java-земле. Таким образом, вы никогда не сможете получить класс Scala с любыми методами не IO из класса Java или интерфейса.

Более того, даже для классов, определенных в Scala, теоретически может быть неперехваченный подкласс, определенный на Java, с нечистыми методами, экземпляры которого могут быть возвращены обратно в Scala в качестве экземпляров родительского класса. Поэтому, если компилятор Scala не может доказать, что данный объект не может быть экземпляром класса, определенного кодом Java, он должен предположить, что любой вызов метода на этом объекте может вызывать код, который был скомпилирован компилятором Java, без уважения законы того, какие функции возвращают результаты не в IO, могут делать. Это заставит почти все быть в IO. Но положить все в IO в точности эквивалентно помещению ничего в IO и просто не отслеживать побочные эффекты!

Итак, Scala предлагает вам писать чистый код, но он не пытается обеспечить, чтобы вы это делали. Что касается компилятора, любой вызов чего-либо может иметь побочные эффекты.