LINUX.ORG.RU

Почему скобки удобны

 , ,


0

2

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

        (stage1 
            @ (free |> List.map (fun l -> l, [l]))) //причинное место
        |> List.groupBy 
            (fun (mline1, lines1) (mline2, lines2) ->
                Math.Abs(mline1.x-mline2.x) < 0.1 
                && Math.Abs(mline1.y-mline2.y) < 0.1)
       (List.groupBy 
	(lambda (mline1 lines1 mline2 lines2)
	  (and (< (Math.Abs (- mline1.x mline2.x) 0.1))
	       (< (Math.Abs (- mline1.y mline2.y) 0.1))))
	(@ stage1 
	   (List.map (lambda (l) (list l (list l))) 
		     free)))))

Я в свое время понял, что многие ЯП от лиспа по кол-ву скобок далеко не ушли, просто кучкуют их по другому принципу и иногда заменяют разными их вариациями и отступами.

deterok ★★★★★ ()

я обязательно требуется во всех этих языках — делать длинные выражения?

нельзя сделать несколько маленьких строчек (выражений), вместо одного длинного выражения?

user_id_68054 ★★★★★ ()
Последнее исправление: user_id_68054 (всего исправлений: 2)

смотрю, а получается как на лиспе

Ты постиг дзен.

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

типо так -

    let tmp1 = free |> List.map (fun l -> l, [l])
    let tmp2 = stage1 @ tmp1
    let result =
        tmp2
        |> List.groupBy 
            (fun (mline1, lines1) (mline2, lines2) ->
                Math.Abs(mline1.x-mline2.x) < 0.1 
                && Math.Abs(mline1.y-mline2.y) < 0.1)
это решение мне не нравится.

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

    free 
    |> List.map (fun l -> l, [l])
    |> List.append stage1 
    |> (fun acc -> 
        acc
        |> List.groupBy 
            (fun (mline1, lines1) (mline2, lines2) ->
                Math.Abs(mline1.x-mline2.x) < 0.1 
                && Math.Abs(mline1.y-mline2.y) < 0.1))

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Да, в эфшарпе либо скобки, либо каскады турисазов :(

buddhist ★★★★★ ()

одинаково мутный код, вообще никакой разницы.

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

Я и указываю на сходство, потому что и там и там указан явно порядок вычисления. Если порядок не указывать(убрать скобки из f# кода), то будет не очевидное поведение, а к тому же - не правильное. Поэтому, по-моему, когда указывается явно структура кода, как в лиспе, то читать это проще, чем когда нужно думать что первым вычислится.

pseudo-cat ★★★ ()
Ответ на: комментарий от buddhist

А какие ещё языки не заставляют использовать скобки и не дают двусмысленность порядка вычисления?

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat
test stage1 = groupBy (((<) 0.1 .). dist)
            . (stage1++)
	    . map (\l -> (l,[l]))
  where
    dist (a,_) (b,_) = (max `on` abs) (x a - x b) (y a - y b)

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

qnikst ★★★★★ ()

А ты не пиши на всяких борщехлебских маргинальных говноязыках, тогда и скобки лишние не понадобятся. Пиши на Java.

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

код совершенно не то делает, у меня такая последовательность действий -
1) (free |> List.map (fun l -> l, [l]))
2) (stage1 @ 1))

Если переписать это как в яве какой-нибудь, получится -

@(stage1, List.map(free, (fun l -> l,[])))
, по сути те же скобки. А как будет на том ЯП, который ты привёл?

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

если @ это объединение списков, а f |> g значит g применить к f- то мой код делает именно это.

qnikst ★★★★★ ()
Последнее исправление: qnikst (всего исправлений: 2)
Ответ на: комментарий от qnikst

stage++ имеет тип List -> List?

Я вообще не вижу в твоём коде использования free

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

А какие ещё языки не заставляют использовать скобки и не дают двусмысленность порядка вычисления?

Forth. Там скобок нет вообще, а порядок вычислений всегда строго фиксирован. Можно сказать — «антилисп» :)

KRoN73 ★★★★★ ()
Ответ на: комментарий от pseudo-cat

stage++ имеет тип List -> List?

да

Я вообще не вижу в твоём коде использования free

конечно, т.к. использована η-редукция, но если тебя это напрягает, (хотя странно что напрягает, т.к. вопросов к groupBy у тебя не возникло, а там тоже ни одного параметра нету), то перепишу:

test stage1 free = groupBy (\a b -> dist a b < 0.1)
            $ (\z -> stage1++z)
	    $ map (\l -> (l,[l])) free
  where
    dist (a,_) (b,_) = max (abs $ x a - x b) (abs $ y a - y b)

так понятнее?

qnikst ★★★★★ ()

(lambda (l) (list l (list l)))

Больше списков!

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

не понятно, это на чём?)

Что делает оператор «$»? Я, интуитивно, читаю это так - применить groupBy к (\z -> stage1++z), который в свою очередь применяется к map (\l -> (l,[l])) free. То есть оператор $ работает по типу карринга, только не прямого, а обратного. А как на самом деле?

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Forth и Factor, конечно :) Еще в Smalltalk часто получается так, что скобок не очень много

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

Ну здесь на самом деле стоит написать (lambda (l) (list l l)), я просто по фшарповому на лиспе пытался)

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

haskell, я ж больше ничего не умею // его тожн не умею.

Что делает оператор «$»?

Да, ты понял правильно (вроде), но распишу полностью:

infixr 0 $
($) :: (a -> b) -> a -> b       -- Defined in ‘GHC.Base’
f $ x = f x

т.е. функция слева от $ применяется к аргументу справа от $, поскольку функция имеет минимальный приоритет и правоассоциативна, то захватывает все до конца, таким образом код вида (this (is (very (lisp (like (expresssion)))))) можно переписать как this $ is $ very $ lisp $ like $ expression.

Часто используется в подобном коде:

foo = bracket (createResource)
              (freeResource) $ \res -> do
                  куча кода

тут мы создаем ресурс, после завершения гарантировано его очищаем (даже в случае исключений (*)) и имеем функцию с ним, или forM list $ \item -> ....

(*) не гарантировано, если главный тред выйдет, а мы не в нём, то freeResource может быть не вызвано.

qnikst ★★★★★ ()
Последнее исправление: qnikst (всего исправлений: 3)
Ответ на: комментарий от qnikst

Я понял, спасибо, НО -

функция имеет минимальный приоритет и правоассоциативна

правоассоциативна

если не знать этого, то возникают вопросы! Правда, если не знаешь этого, то, видимо, на Хаскеле и не пишешь.

pseudo-cat ★★★ ()
Ответ на: комментарий от KRoN73

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

pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Ребол, например

 replace/all copy body 'y [reverse y] 

Скобочки вокруг reverse y - это блок, они не для порядка вычислений. Но вобще функция сама может задавать какие аргументы у нее вычисляются, а какие нет и из-за этого выражение типа

f a g h b c 
с функциями f, g, h может соответствовать хаскельному
f a g (h b) c
а может и нет :)

loz ★★★★★ ()
Последнее исправление: loz (всего исправлений: 2)
Ответ на: комментарий от pseudo-cat

Правда, если не знаешь этого, то, видимо, на Хаскеле и не пишешь.

ну.. новички иногда рукаются на . и $, но очень быстро привыкают.

тут ну со всеми операторами возникает эта проблема: или ты используешь формат как у инопланетян типа фортовского, или делаешь так чтобы удобно было писать и выглядело красиво, но приходится чуть-чуть побольше знать об операторах. На мой взгляд выделение операторов с очень низкими и очень высокими приоритетами не сильно мешает пониманию, но при этом упрощает код. Т.е. в выражении a - b < 0.1 && c - d < 0.1 действительно скобки не помешают даже если в итоге скобки расставятся правильно.

P.S. кстати в пакете lens есть ещё оператор &, который работает наоборот и позволяет писать, что-то вроде "hello" & length & succ, т.е. к hello применяется сначала length, и к результату применяется succ.

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

хоть бы пояснил что здесь происходит, а то смотришь на replace/all:

replace target search replace

Arguments:

target - Series that is being modified. (must be: series)

search - Value to be replaced.

replace - Value to replace with.

и не понимаешь при чём здесь [reverse y]

pseudo-cat ★★★ ()
Ответ на: комментарий от qnikst

скобок нет

groupBy (((<) 0.1 .). dist)

. map (\l -> (l,[l]))

сериоусли?

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

У тебя в коде композиция а не аппликация. (f . g) $ x не то же самое, что (f (g x))

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

Хе-хе, в том то и все дело, реально порядок такой:

replace/all (copy body) 'y [reverse y] 

а контекст такой:

proto: [x [integer!] y [string!]]

body: [
    print x
    print y
]

;-- alternate expression of a function equivalent to foo
foo-alternate: function proto
    body

bar: function proto
    replace/all copy body 'y [reverse y]

в функции bar все вхождения y в копии body заменятся на [reverse y], ну и строка - второй аргумент будет напечатана задом наперед при вызове.

loz ★★★★★ ()
Последнее исправление: loz (всего исправлений: 2)
Ответ на: комментарий от qnikst

ну.. новички иногда рукаются на . и $

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

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

нужна аппликация

композиция, селффикс

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

Нет, не то же самое. f (g x) - последовательная аппликация двух ф-й, (f . g) $ x («f . g $ x» не пишут, это плохой стиль) - аппликация ф-и (f . g). В какой вселенной это может быть одним и тем же?

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

Загляни в любой серьезный проект-нефакториал на хекедже.

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

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

как видишь, если бы это было написанно на лиспе - (replace/all (copy body) 'y (reverse y)) или на другом яп, где нужно явно разделять выражения, то вопросов не было бы.

А как переписать такое с $ в Хаскеле?

pseudo-cat ★★★ ()
Ответ на: комментарий от qnikst

Анон выше твоего коммента написал, разница в «создании» новой функции из f и g.

loz ★★★★★ ()
Ответ на: комментарий от pseudo-cat

Только '(reverse y) в конце, блок тут не вычисляется.

loz ★★★★★ ()
Ответ на: комментарий от anonymous
[f . g] = \x -> f (g x)
[f $ x] = f x
[f . g $ x] = /definition of '$'/
[(f . g) x] = /definition of '.'/
[(\y -> f (g y)) x] = /substitute x/
[f (g x)]   = /definition of $/
[f $ g x]

ваши предложения?

qnikst ★★★★★ ()
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от pseudo-cat

А как переписать такое с $ в Хаскеле?

Думаю можно, вопрос в том что в некоторых случаях функция сама не хочет вычислять аргумент, как например help - это функция, а не хак интерпретатора, и она принимает любой объект не вычисляя его, например help quit покажет справку, в не выполнит quit.

loz ★★★★★ ()

Чё сказать-то хотел? А в smalltalk * и + имеют одинаковый приоритет, так что писать нужно не 3+4*5, а 3+(4*5). СКОБОЧКИ!!!!!111

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

в вот вывод core, для особо неверующих:

ku f g x = f . g $ x

zu f g x = f $ g x
----

T.ku =
  \ (@ b_aM0)
    (@ c_aM1)
    (@ s_aM2)
    (f_asK :: b_aM0 -> c_aM1)
    (g_asL :: s_aM2 -> b_aM0)
    (x_asM :: s_aM2) ->
    f_asK (g_asL x_asM)

T.zu =
  \ (@ t_aLy)
    (@ s_aLz)
    (@ t1_aLA)
    (f_asN :: s_aLz -> t_aLy)
    (g_asO :: t1_aLA -> s_aLz)
    (x_asP :: t1_aLA) ->
    f_asN (g_asO x_asP)

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

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

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

    [1 .. 9]
    |> List.append 
        [10 .. 20] |> List.filter (fun a -> a % 2 = 0)
pseudo-cat ★★★ ()
Ответ на: комментарий от loz

Думаю можно

вопрос в том, как переписать такое - (f1 (f2 a) (f3 b)) , то есть когда ф-ция, которую применяем вызывается от нескольких аргументов, которые сами являются результатом вызова других ф-ций, так ведь не прокатит - f1 f2 $ a f3 $ b я надеюсь.

pseudo-cat ★★★ ()
Ответ на: комментарий от loz

replace/all copy body 'y [reverse y]

на самом деле это жесть какая-то, представь что ф-ция copy принимает 2 аргумента, или 2 аргумента и 1 из них опциональный(если такое там вообще есть). То есть нам надо считать кол-во аргументов и определять что ф-ция а что аргумент?

replace/all copy body 0 100 findkey 300 hashtable 100 [reverse y] 
(replace/all (copy body 0 100)
    (findkey 300 hashtable 100)
    [reverse y] )
pseudo-cat ★★★ ()
Ответ на: комментарий от pseudo-cat

Я не знаю хороших способов переписать такое выражение.

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