Какой тип области видимости использует Haskell?
Вопрос
Я пытаюсь выяснить, использует ли Haskell динамическую или статическую область видимости.Я понимаю, что, например, если вы определяете:
let x = 10
затем определите функцию
let square x = x*x
У вас есть 2 разных "x", и означает ли это, что он имеет динамическую область видимости?Если нет, то какую область видимости он использует и почему?
Кроме того, могут ли переменные Haskell иметь псевдонимы (другое имя для одной и той же ячейки памяти / значения)?
Спасибо.
Решение
Что-то в ваших высказываниях не так...
- В Haskell нет изменяемых переменных, только определения (или неизменяемые переменные).
- Переменная ячейка памяти — это концепция, которой нет в Haskell.
В вашем примере Икс является нет 10 в функции — это просто аргумент квадрата, который может принимать любое значение (тип можно указать позже), в данном случае 10, но только в этом случае.
Вот пример псевдонимов, предоставленных Курт Сэмпсон:
import Data.IORef
main :: IO ()
main = do x <- newIORef 0 -- write 0 into x
readIORef x >>= print -- x contains 0
let y = x
readIORef y >>= print -- y contains 0
writeIORef x 42 -- write 42 into x
readIORef y >>= print -- y contains 42
Другие советы
Haskell использует (в широком смысле) точно такую же лексическую область, как и большинство других языков.
например.
x = 10
Приводит к значению, на которое ссылается x
в глобальном масштабе, тогда как
square x = x * x
приведет к x
будучи лексически ограниченным до функционального квадрата.Это может помочь, если вы подумаете о том, что приведенная выше форма является синтаксической тонкостью для:
square = \ x -> x * x
Что касается вашего другого вопроса, я не уверен, что вы подразумеваете под псевдонимами
Отвечая только на вторую часть вопроса:
Вы можете иметь несколько псевдонимов для одной и той же «ячейки памяти», но, поскольку все они неизменяемы, в большинстве случаев это не имеет значения.
Тупой пример:
foo x y = x * y
bar z = foo z z
Когда внутри foo
звонили из bar
, оба x
и y
явно имеют одно и то же значение.Но поскольку вы не можете изменить ни x
или y
, вы даже не заметите.
Поскольку на первую часть вопроса уже ответили другие, вот вторая часть:
Я предполагаю, что aliasing
ты имеешь в виду one name for another
.Поскольку Haskell — функциональный язык, а функции в любом случае ведут себя как обычные идентификаторы, вы можете сделать это следующим образом:
y = x
который будет определять псевдоним y
для функции x
.Обратите внимание, что все является функцией.Даже если это похоже на "переменная", это просто нулевая функция, не принимающая аргументов.Псевдонимы типов выглядят следующим образом:
type Function = Double -> Double
который будет определять псевдоним Function
для типа Double -> Double
Haskell использует статические вложенные области видимости.Что немного сбивает с толку по сравнению с другими языками, имеющими статические вложенные области видимости, так это то, что областью действия имени является блок, включающий тесты, предшествующие его определению..Например
evens = 0 : map (+1) odds
odds = map : (+1) evens
здесь слово «шансы» входит в определение «четов», несмотря на тот удивительный факт, что «шансы» еще не определены.(В примере определяются два бесконечных списка четных и нечетных чисел.)
Мертвым языком с аналогичным правилом области видимости была Modula-3.Но Haskell немного сложнее: вы можете попытаться «переопределить» переменную в той же области, но вместо этого вы просто вводите другое уравнение рекурсии.Это ловушка для людей, которые впервые изучили ML или Scheme:
let x = 2 * n
x = x + 1 -- watch out!
Это совершенно хороший ML или Scheme let*, но Haskel имеет семантику Scheme letrec без ограничений на значения лямбда.Неудивительно, что это сложная штука!
В вашем примере глобальное определение x затеняется локальным определением x.В Haskell область видимости переменной определяется статическим чтением исходного кода — это называется лексической областью видимости, но можно получить что-то похожее на динамическую область видимости с неявными параметрами (но это может привести к некоторому неожиданному поведению (я читал;сам никогда не пробовал)).
Подводя итог другим ответам кратко:
- лексическая область видимости
- псевдонимы — это так же просто, как
x = 1; y = x
но обычно это не имеет значения, потому что вещи неизменны.
А let
синтаксис, который вы используете в своем примере, выглядит так, как будто он находится в интерактивном ghci>
быстрый.Все в интерактивном режиме происходит внутри монады ввода-вывода, поэтому там все может оказаться более изменчивым, чем обычно.
Ну, как я думаю, люди уже сказали, что в Haskell нет переменных, которые есть в большинстве других языков, в нем есть только выражения.В вашем примере let x = 10
x — это выражение, которое всегда оценивается как 10.Фактически вы не сможете изменить значение x позже, хотя вы можете использовать правила области видимости, чтобы скрыть его, определив x как другое выражение.
Да, у Haskell есть псевдонимы.Попробуйте эту небольшую программу:
import Data.IORef
main :: IO ()
main = do x <- newIORef 0 -- write 0 into x
readIORef x >>= print -- x contains 0
let y = x
readIORef y >>= print -- y contains 0
writeIORef x 42 -- write 42 into x
readIORef y >>= print -- y contains 42