Mam problem z wprowadzaniem poleceń wielowierszowych w ghci.
Poniższy dwuwierszowy kod działa z pliku:
addTwo :: Int -> Int -> Int
addTwo x y = x + y
Ale kiedy wchodzę w ghci, pojawia się błąd:
<interactive>:1:1: error:
Variable not in scope: addTwo :: Int -> Int -> Int
Próbowałem też umieścić kod w środku :{ ... :}
, ale one również nie działają w tym przykładzie, ponieważ jest to po prostu dołączanie wierszy do jednej linii, co nie powinno mieć miejsca.
Używam WinGHCi w wersji 2011.2.0.1
Odpowiedzi:
W większości przypadków możesz polegać na wnioskowaniu o typie, aby opracować podpis za Ciebie. W Twoim przykładzie wystarczy:
Prelude> let addTwo x y = x + y
Jeśli naprawdę potrzebujesz definicji z podpisem typu lub jeśli twoja definicja obejmuje wiele linii, możesz to zrobić w ghci:
Prelude> :{ Prelude| let addTwo :: Int -> Int -> Int Prelude| addTwo x y = x + y Prelude| :} Prelude> addTwo 4 7 11
Zauważ, że możesz również wcisnąć to w jedną linię:
Prelude> let addTwo :: Int -> Int -> Int ; addTwo x y = x + y
Więcej informacji na temat interakcji z ghci można znaleźć w interaktywnej ocenie w sekcji instrukcji w dokumentacji.
źródło
let
rozpoczyna blok; wpisy w bloku są grupowane według wcięć; a pierwszy niebielony znak w bloku ustawia wcięcie, według którego są one zgrupowane. Ponieważ pierwszym niebiałym znakiem wlet
powyższym bloku jest znaka
ofaddTwo
, wszystkie wiersze w bloku muszą być wcięte dokładnie tak głęboko, jak toa
.Rozwiąż ten problem, uruchamiając GHCI i wpisując
:set +m
:Prelude> :set +m Prelude> let addTwo :: Int -> Int -> Int Prelude| addTwo x y = x + y Prelude| Prelude> addTwo 1 3 4
Bum.
To, co się tutaj dzieje (i mówię głównie do ciebie , osoby szukającej pomocy podczas pracy w Learn You A Haskell ), to fakt, że GHCI to interaktywne środowisko, w którym zmieniasz wiązania nazw funkcji w locie. Musisz zawinąć definicje funkcji w
let
blok, aby Haskell wiedział, że masz zamiar coś zdefiniować. To:set +m
jest skrótem dla konstrukcji:{
kodu wielowierszowego:}
.Białe znaki są również istotne w blokach, więc musisz dodać wcięcie definicji funkcji po definicji typu o cztery spacje, aby uwzględnić cztery spacje w
let
.źródło
echo ':set +m' >> ~/.ghci
aby to ustawienie było trwałe.let
samego siebie w pierwszej linii, wtedy cała reszta nie musi być w ogóle wcięta. gdzie białe znaki naprawdę się liczą, to nie może być końcowych spacji w liniach. końcowe białe znaki liczą się jako dodatkowe Enter i przerywają wieloliniowy blok.Zastosowanie
let
:Prelude> :{ Prelude| let addTwo :: Int -> Int -> Int Prelude| addTwo x y = x + y Prelude| :} Prelude> addTwo 2 3 5
źródło
Począwszy od GHCI wersji 8.0.1 ,
let
nie jest już wymagane do zdefiniowania funkcji na REPL.Więc to powinno działać dobrze dla Ciebie:
λ: addTwo x y = x + y λ: addTwo 1 2 3 λ: :t addTwo addTwo :: Num a => a -> a -> a
Wnioskowanie o typie Haskella zapewnia uogólnione typowanie, które działa również dla pływaków:
λ: addTwo 2.0 1.0 3.0
Jeśli musisz podać własne wpisywanie, wydaje się, że będziesz musiał użyć
let
połączenia z wejściem wielowierszowym (użyj,:set +m
aby włączyć wprowadzanie wielowierszowe w GHCI):λ: let addTwo :: Int -> Int -> Int | addTwo x y = x + y | λ: addTwo 1 2 3
Ale pojawią się błędy, jeśli spróbujesz przekazać coś innego niż z
Int
powodu niepolimorficznego pisania:λ: 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
źródło
Aby rozwinąć odpowiedź Aarona Halla , przynajmniej w wersji GHCi 8.4.4 nie musisz używać
let
z deklaracjami typu, jeśli używasz:{
:}
stylu. Oznacza to, że nie musisz się martwić dodawaniem wcięcia z 4 spacjami w każdym kolejnym wierszu w celu uwzględnienialet
, co znacznie ułatwi wpisywanie dłuższych funkcji lub w wielu przypadkach kopiowanie i wklejanie (ponieważ oryginalne źródło prawdopodobnie nie będzie miało prawidłowe wcięcie):λ: :{ | addTwo :: Int -> Int -> Int | addTwo x y = x + y | :} λ: addTwo 1 2 3
Aktualizacja
Alternatywnie możesz włączyć wielowierszowy tryb wprowadzania za pomocą
:set +m
, a następnie wpisaćlet
samodzielnie, nacisnąć Enter, a następnie wkleić definicje bez konieczności wcięcia.Jednak wydaje się, że nie działa to z niektórymi blokami kodu, takimi jak:
class Box a where mkBox :: a -> Boxes.Box
Ale
:{
,:}
technika robi.źródło
:{
, a następnie w następnym wierszulet
samodzielnie, a następnie wkleić definicje bez żadnego dodanego wcięcia, a następnie zakończyć za pomocą:}
. :) a przy wielowierszowym trybie wprowadzania set (:set +m
) nie potrzebowałeś nawet poleceń nawiasów klamrowych, o ile nie było końcowych spacji w liniach kodu.:set +m
możesz po prostu użyćlet
na własnej linii? Więc możesz - to super. Dziękuję Ci.let
a następnie znak nowej linii nie działa. Zobacz moją edycję.