Багаторядкові команди в GHCi


135

У мене виникають проблеми з введенням багаторядкових команд в ghci.

Наступний дворядковий код працює з файлу:

addTwo :: Int -> Int -> Int
addTwo x y = x + y

Але коли я входжу в ghci, я отримую помилку:

<interactive>:1:1: error:
    Variable not in scope: addTwo :: Int -> Int -> Int

Я також спробував вставити код всередину :{ ... :}, але вони також не працюють для цього прикладу, тому що це просто додавання рядків в один рядок, що не повинно бути так.

Я використовую WinGHCi, версія 2011.2.0.1


Відповіді:


184

Більшу частину часу ви можете розраховувати на висновок типу, щоб розробити підпис для вас. У вашому прикладі достатньо наступного:

Prelude> let addTwo x y = x + y

Якщо ви дійсно хочете визначення з підписом типу або ваше визначення охоплює кілька рядків, ви можете зробити це в ghci:

Prelude> :{
Prelude| let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y 
Prelude| :}
Prelude> addTwo 4 7
11

Зауважте, що ви також можете видавити це на один рядок:

Prelude> let addTwo :: Int -> Int -> Int ; addTwo x y = x + y

Детальніше про взаємодію з ghci можна дізнатися з Інтерактивного оцінювання в розділі підказок документації.


1
Дуже дякую за обидва рішення. Але у мене є ще одне пов'язане питання: чому в другому рядку (перед addTwo) потрібні чотири провідні пробіли? І це має бути точним, якщо менше або більше заготовок, то помилка.
R71

9
@Rog letпочинає блок; записи в блоці групуються за відступами; і перший символ, який не є пробілом у блоці, задає відступ, за яким вони групуються. Оскільки перший непробільний символ у letвищезазначеному блоці є aрівним addTwo, всі рядки в блоці повинні бути відступними точно так само глибоко a.
Даніель Вагнер

Дякую. Я також помітив, що в інших блоках let / where. Це велика відмінність від інших мов, де пробіли ігноруються, тому у мене виникли певні труднощі в розумінні цього.
R71

125

Вирішіть цю проблему, запустивши GHCI і набравши :set +m:

Prelude> :set +m
Prelude> let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude| 
Prelude> addTwo 1 3
4

Бум.


Що тут відбувається (і я говорю здебільшого з вами , людина, гуглючи на допомогу, працюючи через « Learn You A Haskell» ), - це те, що GHCI - це інтерактивне середовище, де ви змінюєте прив’язки до імен функцій на ходу. Ви повинні загортати визначення своїх функцій у letблок, щоб Haskell знав, що ви збираєтесь щось визначити. Даний :set +mматеріал є скороченим для багатолінійної конструкції :{ коду :} .

Пробіл також має велике значення в блоках, тому вам доведеться відступити визначення функції після визначення типу чотирма пробілами для обліку чотирьох пробілів у let.


5
Так просто, але не очевидно. Мені хотілося кричати на книгу, яку я використовував, щоб не сказати про це на сторінці 1!
Тім

2
З оболонки Linux, echo ':set +m' >> ~/.ghciщоб зробити цю настройку стійкою.
truthadjustr

ви можете мати letсебе на першому рядку, тоді все решта зовсім не потрібно відступати. де пробіл справді підраховується, там на ваших лініях не повинно бути пробілів. пробіл пробігу вважається додатковим Enter і розбиває багаторядковий блок.
Буде Нісс


5

Станом на GHCI версії 8.0.1 , letбільше не потрібно визначати функції в REPL.

Отже, це повинно працювати для вас:

λ: addTwo x y = x + y
λ: addTwo 1 2
3
λ: :t addTwo
addTwo :: Num a => a -> a -> a

Хаспекський тип виводу забезпечує узагальнене введення тексту, яке працює і для плавців:

λ: addTwo 2.0 1.0
3.0

Якщо вам потрібно ввести власний текст, вам здається, що вам потрібно буде використовувати в letпоєднанні з багаторядковим введенням (використовувати :set +mдля включення багаторядкового введення в GHCI):

λ: let addTwo :: Int -> Int -> Int
 |     addTwo x y = x + y
 | 
λ: addTwo 1 2
3

Але ви отримаєте помилки, якщо спробуєте передати що-небудь, окрім Intвашого не-поліморфного введення тексту:

λ: addTwo 2.0 1.0

<interactive>:34:8: error:
     No instance for (Fractional Int) arising from the literal 2.0
     In the first argument of addTwo’, namely 2.0
      In the expression: addTwo 2.0 1.0
      In an equation for it’: it = addTwo 2.0 1.0

2

Щоб розширити відповідь Аарона Холла , принаймні у версії GHCi 8.4.4, вам не потрібно використовувати letдекларації типу, якщо ви використовуєте :{ :}стиль. Це означає, що вам не доведеться турбуватися про додавання 4-пробільних відступів у кожному наступному рядку для обліку let, що робить більш довгі функції набагато простішими вводити або, в багатьох випадках, копіювати-вставляти (оскільки початкове джерело, ймовірно, не матиме правильний відступ):

λ: :{
 | addTwo :: Int -> Int -> Int
 | addTwo x y = x + y
 | :}
λ: addTwo 1 2
3

Оновлення

В якості альтернативи ви можете увімкнути багаторядковий режим введення :set +m, а потім введітьlet самостійно, натиснути Enter, а потім вставити визначення без відступів.

Однак, схоже, це не працює з деякими кодовими блоками, такими як:

class Box a where
  mkBox :: a -> Boxes.Box

Але :{, :}технік робить.


1
насправді, навіть раніше, ви можете ввести :{, а потім у наступному рядку letсамостійно, а потім вставити свої визначення без доданого відступу, а потім закрити :}. :) і при встановленому багаторядковому режимі введення ( :set +m) вам навіть не потрібні команди дужок, доки в кодових рядках не було пробілів.
Буде Нісс

А, так що з :set +mтобою можна просто використовувати letна своїй лінії? Так можна - це круто. Дякую.
davidA

Хм, я знайшов деякі випадки, коли просто набрати letпотім новий рядок не працює. Дивіться мою редакцію.
davidA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.