Czy możliwe jest wdrożenie myCycle
bez wymieniania myCycle
lub xs
na prawej stronie?
Odpowiedź brzmi: tak i nie (niekoniecznie w tej kolejności).
Inne osoby wspomniały o stałym punkcie połączenia. Jeśli masz kombinator o stałym punkcie fix :: (a -> a) -> a
, to jak wspominasz w komentarzu do odpowiedzi Pubby'ego, możesz napisać myCycle = fix . (++)
.
Ale średnia definicja fix
to:
fix :: (a -> a) -> a
fix f = let r = f r in r
-- or alternatively, but less efficient:
fix' f = f (fix' f)
Należy zauważyć, że definicja fix
polega wspomnieć zmienną lewy-boczny z prawej strony jego definicji (r
w pierwszej definicji, fix'
w drugim). Tak więc to, co do tej pory zrobiliśmy, to zepchnąć problem do zaledwie fix
.
Interesującą rzeczą jest, aby pamiętać, że Haskell jest oparta na rachunku lambda wpisany, i nie bez powodu technicznej najbardziej wpisywanych kamieni lambda są zaprojektowane tak, że nie może„natywnie” wyrazić operator paradoksalny. Języki te stają się Turing-complete, jeśli dodasz dodatkową funkcję "na wierzchu" rachunku bazowego, która pozwala na obliczanie stałych punktów. Na przykład dowolny z nich będzie:
- Dodaj
fix
jako prymitywu do rachunku.
- Dodaj rekursywne typy danych (które ma Haskell, jest to inny sposób definiowania
fix
w Haskell).
- Pozwolić, aby definicje odnosiły się do definiowanego identyfikatora po lewej stronie (który ma również Haskell).
Jest to przydatna rodzaj modułowości dla wielu powodów, jeden jest, że rachunek lambda bez punktów stałych jest również spójny dowód system logiki, inny że fix
programy nie- w wielu takich systemów mogą być sprawdzone, aby zakończyć .
EDIT: Oto fix
napisane rekurencyjnych typów. Teraz definicja samego fix
nie jest rekurencyjny, ale definicja typu Rec
jest:
-- | The 'Rec' type is an isomorphism between @Rec [email protected] and @Rec a -> [email protected]:
--
-- > In :: (Rec a -> a) -> Rec a
-- > out :: Rec a -> (Rec a -> a)
--
-- In simpler words:
--
-- 1. Haskell's type system doesn't allow a function to be applied to itself.
--
-- 2. @Rec [email protected] is the type of things that can be turned into a function that
-- takes @Rec [email protected] arguments.
--
-- 3. If you have @foo :: Rec [email protected], you can apply @[email protected] to itself by doing
-- @out foo foo :: [email protected] And if you have @bar :: Rec a -> [email protected], you can do
-- @bar (In bar)@.
--
newtype Rec a = In { out :: Rec a -> a }
-- | This version of 'fix' is just the Y combinator, but using the 'Rec'
-- type to get around Haskell's prohibition on self-application (see the
-- expression @out x [email protected], which is @[email protected] applied to itself):
fix :: (a -> a) -> a
fix f = (\x -> f (out x x)) (In (\x -> f (out x x)))
'myCycle = \ xs -> let ys = xs ++ ys in ys'. Napisano 'fix'. –