LINUX.ORG.RU

[haskell] покритикуйте программу

 


0

0

Только не спрашивайте, зачем она :-)

Задаётся натуральное число n. Если оно нечётное, то n = 3n+1, если оно чётное, то n = n/2. И так до тех пор, пока n ≠ 1.

Как результат интересны все промежуточные числа.

geblist :: [Integer] -> [Integer]
geblist (n:ns)
    | n == 1 = (n:ns)
    | otherwise = geblist (geb n : (n:ns))


geb :: Integer -> Integer
geb n
    | n == 1 = 1
    | odd n  = 3*n + 1
    | otherwise = n `div` 2

gebseq :: Integer -> [Integer]
gebseq n = reverse (geblist [n])

main = print (gebseq 27)

Вывод:

[27,82,41,124,62,31,94,47,142,71,214,107,322,161,484,242,121,364,182,91,274,137,412,206,103,310,155,466,233,700,350,175,526,263,790,395,1186,593,1780,890,445,1336,668,334,167,502,251,754,377,1132,566,283,850,425,1276,638,319,958,479,1438,719,2158,1079,3238,1619,4858,2429,7288,3644,1822,911,2734,1367,4102,2051,6154,3077,9232,4616,2308,1154,577,1732,866,433,1300,650,325,976,488,244,122,61,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]

☆☆

Последнее исправление: ip1981 (всего исправлений: 3)

n == 1 = (n:ns)

n == 1 = 1

Я хаскелей не знаю, но...

a3
()

Зачем нужен хаскель?

(defun f (&optional (start 27))
  (loop for n = start then (if (oddp n)
                             (1+ (* 3 n))
                             (ash n -1))
        collect n
        until (= n 1)))

(format t "[~{~a~^, ~}]" (f))

Love5an
()

На хаскелле это через рекурсию делается гораздо проще и быстрее чем в вашем варианте.

Но зачем нужен хаскелл?

def geb_seq(n):
    while n != 1:
        yield n
        n = 3 * n + 1 if n % 2 else n / 2
    yield n

print list(geb_seq(27))
ntp
()
Ответ на: комментарий от lester

тут нужны целые числа с неограниченным диапазоном, поскольку сходимость этой последовательности не доказана для любого начального n.

anonymous
()
Ответ на: комментарий от anonymous

по хорошему - да, тут нужно подключать gmplib, например, но опять же такие детали оговариваются особо, как и действия при попадании в бесконечную рекурсию

lester ★★★★
()
geb :: Integer -> Integer 
geb n 
    | n == 1    = 0
    | odd n     = 3*n + 1 
    | otherwise = n `div` 2 

gebseq :: Integer -> [Integer]
gebseq = takeWhile (/=0) . iterate geb

main = print $ gebseq 27
winger
()

Haskell гораздо красивее и позволяет гораздо более математические записи делать.

collatzSteps :: Integer -> [Integer]
collatzSteps n =
  let nextElement n
          | odd n = 3*n + 1
          | otherwise = n `div` 2
  in n : map nextElement (collatzSteps n)

gebseq :: Integer -> [Integer]
gebseq n = takeWhile (/=1) (collatzSteps n) ++ [1]
dmage
()
Ответ на: комментарий от lester

>но опять же такие детали оговариваются особо

нет. подобное с ограничением диапазона выглядит нелепо. например, так сразу и не ясно, что для какого-нибудь небольшого числа мы не вылетим из диапазона. причем нужно проверить каждое начальное значение. легче сразу сделать таблицой.

anonymous
()
Ответ на: комментарий от ip1981
gebseq = takeWhile (/= 1) . iterate f
    where f n = if (odd n) then (3 * n + 1) else (n `div` 2)

main = (print . (take 10) . gebseq) 27
jtootf ★★★★★
()
Ответ на: комментарий от anonymous

я ж не спорю :), вот вам новый вариант - с длинными числами и все так же в три строки:

mpz_class n = 27;
while( n != 1 )
    n = n % 2 ? 3*n+1 : n/2, cout << n.get_str(); 
lester ★★★★
()
Ответ на: комментарий от dmage

>Haskell гораздо красивее и позволяет гораздо более математические записи делать.

это чтобы получить возможное переполнение стека?

anonymous
()
Ответ на: комментарий от naryl

Впрочем, и Схема не нужна.

-module(f).
-export([f/1]).

f(1) ->
    []; 

f(N) when is_number(N) ->
    NN = if
        N rem 2 == 1 ->
            1 + 3 * N;
        true ->
            N div 2
    end,
    [NN|f(NN)].
naryl ★★★★★
()
Ответ на: комментарий от naryl

ага... как и такой код на Erlang :)

gebseq(N) -> 
    geb(N, []).

geb(1, Res) -> 
    lists:reverse([1|Res]);
geb(N, Res) when N rem 2 == 1 ->
    gebseq(1 + 3 * N, [N|Res]);
geb(N, Res) ->
    gebseq(N div 2, [N|Res]).
Cy6erBr4in ★★★
()
Ответ на: комментарий от Cy6erBr4in

мда...

 
gebseq(N) ->  
    geb(N, []). 
 
geb(1, Res) ->  
    lists:reverse([1|Res]); 
geb(N, Res) when N rem 2 == 1 -> 
    geb(1 + 3 * N, [N|Res]); 
geb(N, Res) -> 
    geb(N div 2, [N|Res]). 

Cy6erBr4in ★★★
()
Ответ на: комментарий от naryl

Очевидно, по той причине, что то, что ты накатал, мало того, что выглядит как говно, так еще и не справляется с задачей(внятный вывод).

Вот, кстати, кто еще тут сомневается в превосходстве CL? Из всех приведенных вариантов, на нем - единственный понятный и читаемый, и к тому же самый простой и, практически, самый эффективный.

В отличие от вот такого говна

yield n 
        n = 3 * n + 1 if n % 2 else n / 2 
    yield n 
которое практически хер распарсишь взглядом; и которое тормозит так, что хочется сломать контупер;

вот такого говна

n = n % 2 ? 3 * n + 1 : n / 2, printf( "&d", n ); 
которое мало того, что, аналогично предыдущему, хер поймешь что делает, так еще и может учудить переполнение;

или какого-нибудь хаскельного отблева из буковок, за один вид которого очень хочется настучать как автору кода, так и автору языка по голове

Love5an
()
Ответ на: комментарий от Love5an

obvious fix

> или какого-нибудь лиспового отблева из скобочек, за один вид которого очень хочется настучать как автору кода, так и автору языка по голове

Это я к тому что толсто

winger
()
Ответ на: obvious fix от winger

Какой отблев из скобочек, дурень?

Где ты вот тут его увидел?

(loop for n = start then (if (oddp n)
                           (1+ (* 3 n))
                           (ash n -1))
      collect n
      until (= n 1))
Это же псевдокод практически, чуть ли не литературный английский.

Love5an
()
Ответ на: комментарий от Love5an

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

PS из всех кусков кода в этом треде ЭТО я бы назвал понятным в последнюю очередь

winger
()
Ответ на: комментарий от Love5an
LongInteger n = 27;

while( n != 1 )
{
    if( odd( n ) )
        n = 3 * n + 1;
    else
        n /= 2;
}

вот код на говно-с++, чем он не такой «литературный английский» как вариант на лиспе?

lester ★★★★
()
Ответ на: комментарий от winger

Т.е. ты возражаешь против того, что у хаскеля блевотный засахаренный синтаксис(про то, что он скрывает еще более блевотную семантику сейчас не будем)? Ты на нем много кода видел? Да с ним же только разве перл да c++ с шаблонами по отвратительности соперничать могут.

PS из всех кусков кода в этом треде ЭТО я бы назвал понятным в последнюю очередь

А вот это вот реально троллинг. И ты еще меня троллем называешь?

Love5an
()
Ответ на: комментарий от lester

Ты утрируешь. Во-первых, это код на Си. Во-вторых, до определенного предела, и при должном форматировании, код на Си действительно приятно читать, особенно если не используются указатели, гыгы. Хотя, опять же, парсить мозгом operator precedence - дикая головная боль, иногда.

Love5an
()
Ответ на: комментарий от Love5an

> Во-первых, это код на Си

таки С++ - LongInteger это typedef на класс mpz_class,

lester ★★★★
()
Ответ на: комментарий от Love5an

Как я могу возражать против твоих субъективных суждений? Пока ты не написал ни одного объективного высказывания, которое можно было бы обсудить.

Я в свою очередь высказал свое субъективное мнение о твоем примере

winger
()
Ответ на: комментарий от winger

Пример объективного высказывания: код на лиспе обычно нечитаем для не-лиспера (впрочем это применимо почти к любому языку)

winger
()
Ответ на: комментарий от winger

За объективные суждения у меня и так уже много наминусовано в score :)

Love5an
()
Ответ на: комментарий от winger

Это не объективное высказывание. Это проекция твоих субъективных впечатлений, причина которых - большой опыт писания на отличных от лиспа языках, на окружение.
Меня люди не-программисты говорили, что лисп очень понятен и читаем.

Love5an
()
Ответ на: комментарий от Love5an

Более того, т.к. CL может менять семантику и синтаксис до неузнаваемости, и в этом собственно его суть, спорить о читаемости кода на нем - просто глупо.

Love5an
()
Ответ на: комментарий от Love5an

Мне почему-то кажется, что если показать этот тред не-программисту, то он сможет понять смысл разве что куска кода на C

winger
()
Ответ на: комментарий от winger

(тяну обе руки) я доброволец из зала - возьмите меня!

lester ★★★★
()
Ответ на: комментарий от Love5an

Это же псевдокод практически, чуть ли не литературный английский

| n out |
n   := (Smalltalk getArgv: 1) asInteger.
out := [:x | Transcript << x << ' ' ].

out value: n.

[n ~= 1] whileTrue: [
  n odd
    ifTrue:  [ n := 3 * n + 1 ]
    ifFalse: [ n := n / 2 roundTo: 1 ].
  out value: n]
yoghurt ★★★★★
()
Ответ на: комментарий от Love5an

Это же псевдокод практически, чуть ли не литературный английский.

код на хаскеле: пока элемент не равен 1, генерировать его по правилу %правило%

код на CL: цикл по элементу начать тогда %правило% собирать пока элемент не равен 1

я не сомневаюсь, что на CL можно писать «почти на литературном английском», но в твоём коде я его в упор не вижу

jtootf ★★★★★
()
Ответ на: комментарий от jtootf
Цикл.
Пусть 'n' [сначала] принимает значение 'start', потом - если 'n' нечетно, {1 плюс {умножить три на 'n'}}, в противном случае - {арифметический сдвиг 'n' влево на -1}
собирай 'n' [в список]
до тех пор пока не выполнится условие
                              равенста 'n' и 1

Код на хаскеле у меня проговорить таким образом язык не поворачивается.

Love5an
()
Ответ на: комментарий от Love5an

Код на хаскеле у меня проговорить таким образом язык не поворачивается.

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

jtootf ★★★★★
()
Ответ на: комментарий от ntp
iff = lambda c, a, b: [a, b][c == 0]
z = lambda f: (lambda x: f(lambda z: x(x)(z)))(lambda x: f(lambda z: x(x)(z)))
collatzStep = lambda x: iff( x&1, 3 * x + 1, x >> 1)
head = lambda x: x[0]
cons = lambda x, y: [x] + y
zcollatz = lambda r: lambda n: iff(head(n) == 1, lambda: n, lambda: r(cons(collatzStep(head(n)), n)))()
collatz = z(zcollatz)

print collatz([27])
suzuki
()
Ответ на: комментарий от Love5an

> Это же псевдокод практически, чуть ли не литературный английский.

Lmao. Это что угодно, но не псевдокод. Код выше на пайтоне и то понятнее, так как в твоём варианте слишком много сахара (и цикл дурацкий, да)

suzuki
()
Ответ на: комментарий от Love5an

А так:

[code] import List

collatz = unfoldr collatzStep where collatzStep 0 = Nothing collatzStep 1 = Just (1, 0) collatzStep x = if odd x then Just (x, 3 * x + 1) else Just (x, x `div` 2) [/code]

suzuki
()
Ответ на: комментарий от suzuki
import List

collatz = unfoldr collatzStep
        where
         collatzStep 0 = Nothing
         collatzStep 1 = Just (1, 0)
         collatzStep x = if odd x
                            then Just (x, 3 * x + 1)
                            else Just (x, x `div` 2)
suzuki
()
Ответ на: комментарий от Love5an

Из всех приведенных вариантов, на нем - единственный понятный и читаемый мною

fixed

Miguel ★★★★★
()
Ответ на: комментарий от Love5an

Код на хаскеле у меня проговорить таким образом язык не поворачивается.

Естественно, ибо он проговаривается гораздо проще, без всяких ненужных «циклов».

Miguel ★★★★★
()
Ответ на: комментарий от Cy6erBr4in

> ага... как и такой код на Erlang :)

Ну извиняйте. В (почти) 3 часа ночи осилил только построчный перевод со Схемы.

naryl ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.