avva: (moose)
[personal profile] avva
Наткнулся на этот исторический документ, интерпретатор игрушечного фрагмента языка J, написанный в 89-м году создателем родственного языка K.

Если вы не знаете J/APL (как и я; давно хочу изучить, да все как-то...), то предлагаю вам задачу, которую я поставил перед собой из чистого любопытства мазохизма упрямства: прочитайте и поймите эту программу (включая понимание того, как устроен язык, который она интерпретирует) только с листа, не перенося ее в компьютер, не запуская, не переписывая исходники более понятным образом итп.




typedef char C;typedef long I;
typedef struct a{I t,r,d[3],p[2];}*A;
#define P printf
#define R return
#define V1(f) A f(w)A w;
#define V2(f) A f(a,w)A a,w;
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
I *ma(n){R(I*)malloc(n*4);}mv(d,s,n)I *d,*s;{DO(n,d[i]=s[i]);}
tr(r,d)I *d;{I z=1;DO(r,z=z*d[i]);R z;}
A ga(t,r,d)I *d;{A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r);R z;}
V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;}
V2(plus){I r=w->r,*d=w->d,n=tr(r,d);A z=ga(0,r,d);
DO(n,z->p[i]=a->p[i]+w->p[i]);R z;}
V2(from){I r=w->r-1,*d=w->d+1,n=tr(r,d);
A z=ga(w->t,r,d);mv(z->p,w->p+(n**a->p),n);R z;}
V1(box){A z=ga(1,0,0);*z->p=(I)w;R z;}
V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
A z=ga(w->t,1,&n);mv(z->p,a->p,an);mv(z->p+an,w->p,wn);R z;}
V2(find){}
V2(rsh){I r=a->r?*a->d:1,n=tr(r,a->p),wn=tr(w->r,w->d);
A z=ga(w->t,r,a->p);mv(z->p,w->p,wn=n>wn?wn:n);
if(n-=wn)mv(z->p+wn,z->p,n);R z;}
V1(sha){A z=ga(0,1,&w->r);mv(z->p,w->d,w->r);R z;}
V1(id){R w;}V1(size){A z=ga(0,0,0);*z->p=w->r?*w->d:1;R z;}
pi(i){P("%d ",i);}nl(){P("\n");}
pr(w)A w;{I r=w->r,*d=w->d,n=tr(r,d);DO(r,pi(d[i]));nl();
if(w->t)DO(n,P("< ");pr(w->p[i]))else DO(n,pi(w->p[i]));nl();}

C vt[]="+{~<#,";
A(*vd[])()={0,plus,from,find,0,rsh,cat},
(*vm[])()={0,id,size,iota,box,sha,0};
I st[26]; qp(a){R a>='a'&&a<='z';}qv(a){R a<'a';}
A ex(e)I *e;{I a=*e;
if(qp(a)){if(e[1]=='=')R st[a-'a']=ex(e+2);a= st[ a-'a'];}
R qv(a)?(*vm[a])(ex(e+1)):e[1]?(*vd[e[1]])(a,ex(e+2)):(A)a;}
noun(c){A z;if(c<'0'||c>'9')R 0;z=ga(0,0,0);*z->p=c-'0';R z;}
verb(c){I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;}
I *wd(s)C *s;{I a,n=strlen(s),*e=ma(n+1);C c;
DO(n,e[i]=(a=noun(c=s[i]))?a:(a=verb(c))?a:c);e[n]=0;R e;}

main(){C s[99];while(gets(s))pr(ex(wd(s)));}



Я потратил на это немало времени сегодня вечером, но, кажется, добился.

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

Date: 2013-03-20 02:02 am (UTC)
From: [identity profile] kit1980ukr.livejournal.com
Почему вы считаете, что R - родственник J, к тому же близкий?

Date: 2013-03-20 02:49 am (UTC)
From: [identity profile] kirenenko.livejournal.com
Я удивлен, что вы удивлены. Не только я так считаю. J и R (и S) - "векторные"/"матричные" языки, имеющие общий исток (APL) и очень близкий синтаксис. R однако не часто воспринимается и обсуждается как язык программирования. Чаще - как библиотека прикладной статистики.

Date: 2013-03-20 03:25 am (UTC)
From: [identity profile] kit1980ukr.livejournal.com
Векторные языки - согласен.

Общий исток APL - вряд ли для S (R). Люди разные, места разные, время создания примерно одно и тоже...

Насчет "очень близкий синтаксис"... Вот, например, одна и та же по смыслу программа на R и J (http://progopedia.ru/example/fibonacci/)

R:
fib <- function(n) {
  if (n < 2)
    n
  else
    fib(n - 1) + fib(n - 2)
}
print.table(lapply(1:16, fib))

J:
load 'printf'

fibr=: 1:`(-&2 + &fibr -&1) @.(2&<)"0
fstr=: '...' ,~ ,~^:4 '%d, '
fstr printf fibr 1+i.16

Date: 2013-03-20 01:20 pm (UTC)
From: [identity profile] migmit.livejournal.com
Не знаю R, но программа на нём выглядит совершенно понятной.

Date: 2013-03-20 03:11 pm (UTC)
From: [identity profile] kirenenko.livejournal.com
да, я соглашусь на счет синтаксиса, он в R чуть более читаемый, как вы продемонстрировали.

Однако, даже к вашему примеру есть куча вопросов. Векторный язык, а функцию к вектору не применяете? Как так? Вместо этого какой-то lapply, который потом требует какой-то print.table.
То есть, то что "программа на нём выглядит совершенно понятной", как написал migmit - это обманчиво.

fib = function(n){ifelse(n < 2, 1, fib(n-1)+fib(n-2))}
paste(1:16, fib(1:16-1), sep=": ")


Date: 2013-03-23 11:31 am (UTC)
From: [identity profile] p2004r.livejournal.com
более простого кода по моему не существует (никаких тупых циклов по крайней мере нет). просто форматировать надо соответственно.

fib <- function(n){          # объявить функцию
   ifelse(n < 2, 
          1, 
          fib(n-1)+fib(n-2)) # применить рекурсивно
}

paste(1:16,         # склеить вектор 1-16 
      fib(1:16-1),  # с результатами функции
      sep=": ")     # разделитель :_

Date: 2013-04-04 01:02 am (UTC)
From: [identity profile] kirenenko.livejournal.com
Я вас тут ждал, но не дождался.
Во-первых, искренне, спасибо за ваши посты в R-community и за хороший код.

Во-вторых, спасибо за комментирование/форматирование моего кода. Ах, если б R код, который пишут учьоные, был так оформлен. (Кстатте, "1:16-1" тоже заслуживает комментария)

Но. Не-спасибо за не-комментирование кода kit1980ukr, который даже простой пример написал кое-как.
И отдельное не-спасибо за замену = на <- в моем коде.

Date: 2013-04-04 06:31 am (UTC)
From: [identity profile] p2004r.livejournal.com
Я вас тут ждал, но не дождался.

Вы конечно не поверите, но некие флюиды витали :)

Кстатте, "1:16-1" тоже заслуживает комментария

Да, логика алгоритма "размазана" между двумя операторами. Я видел это, но это уже не комментарий кода. Это "шапка" описание, или чунк (как там было? :) "всякого ....?).

PS в конце концов именно так написав автор кода делает код более понятным :) R это вполне себе язык, на котором именно описывают что было сделано с данными (а не "портянки кода" пишут ()хотя если хочет человек, то портянку кода он на чем угодно напишет :))

"Ах, если б R код, который пишут учьоные, был так оформлен.

1)"учьоных" старательно приучают пользовать for() ("они же начинающие") 2) и не редактировать свой код в emacs (там это практически автоматически получается именно в таком виде)

И отдельное не-спасибо за замену = на <- в моем коде.

за исключением когда оператор присваивания не пишут в стандартной для R форме :)

Кроме того a<-b , a->b ; и для того что бы красиво (компактно) оформить код (именно использовав APL-стиля операторы) очень даже может пригодится.
Edited Date: 2013-04-04 06:41 am (UTC)

Date: 2013-03-20 11:41 pm (UTC)
From: [identity profile] raindog-2.livejournal.com
Я бы фибоначчи вот так написал, нерекурсивно:
fib =: 3 : '{. (}.,+/)^:y i.2'
Смысл (для тех кто не читает J) - взять пару чисел, и заменить их на пару из хвоста и суммы чисел. Проделать это N раз, начиная с (0 1), и в конце взять голову пары.

Date: 2013-03-24 07:19 pm (UTC)
From: [identity profile] potan.livejournal.com
Приемы программирования очень похожи. Только синтаксис более читабельный.

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 29th, 2025 08:08 pm
Powered by Dreamwidth Studios