Бен в комментариях к вопросу упоминает родной тип пары, который я собираюсь использовать в этом ответе. Я также собираюсь заменить ваш Nil
типом блока Haskell ()
.
Это немного за пределами того, что вы спрашиваете, но я думаю, что стоит сказать. В Хаскеле трудно поймать понятие «список» в Схеме, если вы не «обманываете» и не используете расширение типа Data.Dynamic
. Это связано с тем, что с точки зрения «чистого», расширенного Haskell трудно, если не невозможно, назначить все списки Scheme одного типа. Это означает, что, хотя Scheme позволяет вам писать функции, которые берут любой список, правильный или неправильный, вам будет трудно сделать то же самое в Haskell (и по понятной причине; неправильные «списки», вероятно, в любом случае не должны существовать).
Так, например, вы в основном решили использовать (a, b)
в качестве типа схемоподобных пар. Теперь предположим, что у нас есть эти списки схем:
(define zero '())
(define one '(1))
(define two '(1 2))
(define three '(1 2 3))
(define four '(1 2 3 4))
Вот простой перевод в терминах пар Haskell, который соответствует тому, как вы это делаете:
zero :: ()
zero = ()
one :: (Integer, ())
one = (1, ())
two :: (Integer, (Integer, ()))
two = (1, (2, ()))
three :: (Integer, (Integer, (Integer, ())))
three = (1, (2, (3, ())))
four :: (Integer, (Integer, (Integer, (Integer, ()))))
four = (1, (2, (3, (4, ()))))
Ключевым моментом является то, что в Scheme вы можете легко написать функцию, которая охватывает все списки:
(define (reverse list)
(foldl cons '() list))
(define (filter pred? list)
(foldr (lambda (elem rest)
(if (pred? elem)
(cons elem rest)
rest))
'()
list))
(define (foldl fn init list)
(if (null? list)
init
(foldl fn (fn (car list) init) (cdr list))))
(define (foldr fn init list)
(if (null? list)
init
(fn (car list)
(foldr fn init (cdr list)))))
В этом переводе на Haskell вы вообще не можете сделать это легко, потому что «списки» разной длины имеют разные типы. И становится еще хуже, если учесть разницу между reverse
(который принимает список длиной n и создает список длиной n ) и filter
(который принимает список длиной n и создает список длиной m ≤ n , так что m может быть известен только во время выполнения).