Haskell в Python: проблема преобразования нескольких функций

Я новичок в программировании, и меня попросили преобразовать 3 функции haskell в python в качестве практического упражнения. 3 функции связаны, так как выход одной используется как вход следующей и так далее.

Я понимаю, что делают функции Haskell, но я понятия не имею, как начать их преобразование!

Это код haskell:

factorial :: Int -> Int
factorial n = product (down n)

product :: [Int] -> Int
product [] = 1
product (a:as) = a * product as

down :: Int -> [Int]
down 0 = []
down n = n : down (n-1)

И это была моя попытка преобразовать его:

class function:
    def down(self):
        if self.n == 0:
            self.lista = []
        else:
            self.lista = range(self.n, 0, -1)

    def product(self):
        for x in self.lista:
            if x == []:
                self.product = 1
            if x != []:
                for i in self.lista:
                    self.product = i * self.product

    def factorial(self):
        self.n = int(raw_input("n="))

        self.fact = self.product(self.down(self.n))

        print self.fact
        raw_input()

c = function()
c.factorial()

Ну, во-первых, я считаю, что это не «прямое преобразование» кода Haskell. Это было бы хорошо, но во-вторых, это не работает.

Это отсутствие опыта программирования убивает меня... может ли кто-нибудь помочь мне с этой проблемой?

Большое спасибо!

Редактировать:

Суть этой проблемы в том, чтобы точно преобразовать haskell в python. Я сам сделал урезанную версию, это был следующий шаг в упражнении ^^


person Edward Coelho    schedule 01.11.2012    source источник
comment
Преобразование кода с одного языка, который вы не совсем понимаете, на другой язык, который вы не совсем понимаете, — ужасный способ научиться программированию. Я бы посоветовал тому, кто дает вам упражнения, сначала довести вас до того, чтобы вы чувствовали себя комфортно при чтении и написании кода на одном языке.   -  person Ben    schedule 02.11.2012


Ответы (2)


Во-первых, выбросьте обертку class — она не нужна.

Прямой перевод Python будет выглядеть примерно так:

# factorial :: Int -> Int
def factorial(n):
    return product(down(n))

# product :: [Int] -> Int
def product(arr):
    if len(arr) == 0: return 1
    a, ar = arr[0], arr[1:]
    return a * product(ar)

# down :: Int -> [Int]
def down(n):
    if n == 0: return []
    return [n] + down(n - 1)

Но рекурсивный стиль здесь не очень питонический. Следующее упражнение: замените рекурсию итерацией, списковыми включениями или вызовами reduce (если на Python2).

person Deestan    schedule 01.11.2012
comment
последнее упражнение, прочитайте о функции factorial в модуле math в stdlib :D - person mgilson; 01.11.2012
comment
О, я поражен тем, как просто это может быть! Не знал, что Haskell так похож на Python. Большое спасибо! - person Edward Coelho; 01.11.2012
comment
Проблема с этим кодом не в том, что он не питонический (т. е. не идиоматический Python), а в том, что у новичка создается ложное впечатление о сходстве между Python и Haskell. Списки Python представляют собой непрерывные массивы, поэтому получение оставшихся элементов — дорогостоящая операция для длинных списков. Другими словами, ar = arr[1:] в Python сильно отличается с точки зрения использования ЦП и памяти от распаковки первого и оставшихся элементов списка в Haskell. - person user4815162342; 01.11.2012
comment
Тьфу, а как теперь передать переменные из одной функции в другую? Я впервые работаю с несколькими функциями, поэтому использовал оболочку класса ^^' - person Edward Coelho; 01.11.2012
comment
@EdwardCoelho Так же, как и в исходном коде Haskell, они задаются как параметры в вызовах функций. :) - person Deestan; 01.11.2012
comment
@ user4815162342 Вот что я имел в виду; рекурсивное построение списка ужасно непитоновское, так как это подход, который не понимает Python. Но да, вы совершенно правы. :) - person Deestan; 01.11.2012

Если вы хотите написать идиоматический Python, избегайте рекурсии.

down(n) пишется как range(n, 0, -1). Используйте xrange, если вам нужна ленивая семантика, которая была бы ближе к духу Haskell.

product(lst) это reduce(operator.mul, lst, 1). (Было бы более идиоматично просто указать цикл, но это короче.)

Отсюда должно быть очевидно, как преобразовать factorial.

person user4815162342    schedule 01.11.2012
comment
Вау, спасибо! Я действительно должен был использовать ленивую семантику и не знал об этом! - person Edward Coelho; 01.11.2012
comment
Если вам нравится ленивая семантика, вам понравятся генераторы. Python ленивее, чем люди думают. :) - person user4815162342; 01.11.2012
comment
@EdwardCoelho Пожалуйста. Если вы нашли ответ полезным, не стесняйтесь нажимать кнопку «Принять». :) - person user4815162342; 01.11.2012
comment
Я, конечно, сделал! Я просто пытаюсь закончить код. Я всегда делаю это, прежде чем принять :p - person Edward Coelho; 01.11.2012
comment
Не могли бы вы пояснить строку {reduce(operator.mul, lst, 1)} немного подробнее, пожалуйста? - person Edward Coelho; 01.11.2012
comment
operator.mul — это функциональный эквивалент оператора умножения. Операция reduce эквивалентна циклу: r = 1; for elem in lst: r *= elem. Некоторые функциональные языки называют эту операцию fold. - person user4815162342; 02.11.2012
comment
Если вам нравится ленивая семантика и возможность использовать значения более одного раза, вы будете ненавидеть генераторы. - person Ben; 02.11.2012