Як визначити функцію в ghci через кілька рядків?


161

Я намагаюся визначити будь-яку просту функцію, яка охоплює кілька рядків у ghci. Візьмемо наступний приклад:

let abs n | n >= 0 = n
          | otherwise = -n

Поки я намагався натиснути Enter після першого рядка:

Prelude> let abs n | n >= 0 = n
Prelude>           | otherwise = -n
<interactive>:1:0: parse error on input `|'

Я також спробував використати команди :{та :}команди, але я не заходжу далеко:

Prelude> :{
unknown command ':{'
use :? for help.

Я використовую GHC Interactive версії 6.6 для Haskell 98 в Linux, що мені не вистачає?


20
Оновіть установку GHC. GHC 6,6 майже 5 років! Останні версії Haskell тут: haskell.org/platform
Дон Стюарт


1
@Mark Цей ОП вже випробував рішення цієї проблеми. Ця проблема пов'язана із застарілими ghci, а не браком знань, що робити. Тут вирішення: оновлення. Рішення є: використання :{, :}.
AndrewC

Відповіді:


124

Для охоронців (як ваш приклад) ви можете просто поставити їх на один рядок, і це працює (охоронці не хвилюються про інтервали)

let abs n | n >= 0 = n | otherwise = -n

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

fact 0 = 1
fact n = n * fact (n-1)

Тоді ви використовуєте дужки з крапками з комою, що розділяють означення

let { fact 0 = 1 ; fact n = n * fact (n-1) }

258

GHCi тепер має режим багатолінійного введення, увімкнено: set + m. Наприклад,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800

39
Встановлення багаторядкового режиму змушує ghciповодитися так, як інтерпретатор Python в цьому плані. Дуже зручно! Насправді ви можете створити .ghciфайл у своєму домашньому каталозі, у який ви ставите, :set +mі режим багатолінійного стану стане типовим для кожного запуску ghci!
kqr

2
Це справді приголомшливо. Але я помітив, що коли я встановлюю своє запит, використовуючи :set prompt "λ "продовжені рядки, скажіть Preludeзамість λ. Будь-який спосіб обійти це?
abhillman

2
Тут ви знайдете патч, щоб визначити нову підказку для продовження ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa

4
Щоб запобігти появі Prelude у рядках продовження, також додайте: встановіть prompt2 "|" у своїх .ghci.
Нік

12
Ви можете повністю уникнути відступу, використовуючи трейлінг let. Просто введіть letнаступний рядок: let⏎. Тоді fac 0 = 1⏎. Тоді fac n = n * fac (n-1)⏎ ⏎ і все закінчилося!
Iceland_jack

62

Дан правильний, але :{і :}кожен з них повинен з'явитися на їх власної лінії:

> :{ 
> let foo a b = a +
>           b
> :}
> :t foo
foo :: (Num a) => a -> a -> a

Це також взаємодіє з правилом компонування, тому при використанні do-notation може бути простіше використовувати дужки та напівколонки явно. Наприклад, це визначення не вдається:

> :{
| let prRev = do
|   inp <- getLine
|   putStrLn $ reverse inp
| :}
<interactive>:1:18:
    The last statement in a 'do' construct must be an expression

Але це працює, коли додаються дужки та напівколонки:

> :{
| let prRev = do {
|   inp <- getLine;
|   putStrLn $ reverse inp;
| }
| :}
> :t prRev
prRev :: IO ()

Це дійсно має значення лише при вставці визначень з файлу, де відступ може змінитися.


Це не працює, якщо у вас є рядок, що закінчується на '=' (з визначенням, наступним у наступному рядку), принаймні у версії 7.6.3.
AdamC

1
Можливо, це не вдається, тому що другий та третій рядки даного місця не є відступними ... (Ще два пробіли.)
Evi1M4chine


7

Якщо ви не хочете , щоб оновити GHC тільки для :{і :}ви повинні будете написати все це на одному рядку:

> let abs' n | n >= 0 = n | otherwise = -n

Мені невідомо жодне окреме визначення в Haskell, яке повинно бути написане в декількох рядках. Сказане дійсно працює в GHCi:

> :t abs'
abs' :: (Num a, Ord a) => a -> a

Для інших виразів, таких як doблоки, вам потрібно буде використовувати синтаксис без компонування з фігурними дужками та крапками з комою (eugh).


0

Я використовую GHCi, версія 8.2.1 на macOS Catalina 10.15.2. Далі, як я з'єднав як функції, так і декларації типу функцій. Зверніть увагу, що вертикальні смуги зліва призначені для декількох ліній GHCi.

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7

1
Якщо ви використовуєте :{і :}вам не потрібно вказувати let перед декларацією про тип, це означає, що не потрібно вводити друге та наступні рядки.
davidA

Дуже дякую, davidA. Саме це я шукав, але не зміг знайти.
Золотий палець

0

Схоже, вставлення обох рядків одночасно або за допомогою контрольного введення для кожного нового рядка зберігає все це разом, принаймні, на https://repl.it/languages/haskell . Ви побачите дві крапки на початку другого рядка. Або помістіть його у файл і: завантажте файл (: l основний). Чому abs не працює з від'ємними числами? О, ви повинні поставити круглі дужки навколо номера.

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.