Learn more languages, especially cross-paradigm. Most languages in a given paradigm will be sufficiently similar that you can get the gist of any code written in it if you're familiar with another language of the paradigm, especially if the code is reasonably written. For example:
(specification)
generic
type Element_Type is private;
type Index is (<>);
type Collection is array(Index) of Element_Type;
with function "<=" (Left, Right : Element_Type) return Boolean is <>;
procedure Gnome_Sort(Item : in out Collection);
(body)
procedure Gnome_Sort(Item : in out Collection) is
procedure Swap(Left, Right : in out Element_Type) is
Temp : Element_Type := Left;
begin
Left := Right;
Right := Temp;
end Swap;
I : Integer := Index'Pos(Index'Succ(Index'First));
J : Integer := I + 1;
begin
while I <= Index'Pos(Index'Last) loop
if Item(Index'Val(I - 1)) <= Item(Index'Val(I)) then
I := J;
J := J + 1;
else
Swap(Item(Index'Val(I - 1)), Item(Index'Val(I)));
I := I - 1;
if I = Index'Pos(Index'First) then
I := J;
J := J + 1;
end if;
end if;
end loop;
end Gnome_Sort;
There's a gnome sort (a.k.a. stupid sort) in Ada. If you're familiar with any loosely structured-imperative programming language you can pretty much figure it out. while
works as you'd likely expect. if
and else
too. loop
and end loop
and end if
and even begin
/end
are pretty obvious. You'll have to do a bit of head-scratching if you're not familiar with languages in the Wirthian tradition (Pascal, the Modulas, the Oberons) to figure out which parts you can safely ignore and which parts you need to pay attention to, but it's not really difficult. The hardest part is "weird" expressions like Index'Pos(Index'Succ(Index'First));
which you can still kind of guess the meaning of from context, especially in the later expression while I <= Index'Pos(Index'Last)
where you might think Index`Pos() is like index.pos() in another language like Python or C++ and won't be completely wrong (though still wrong).
Basically you work it out by knowing the paradigm and knowing how things are generally expressed in said paradigm.
Of course if you're unfamiliar with the paradigm involved you might find it impossible to decode:
(Erlang—functional)
gnome(L, []) -> L;
gnome([Prev|P], [Next|N]) when Next > Prev ->
gnome(P, [Next|[Prev|N]]);
gnome(P, [Next|N]) ->
gnome([Next|P], N).
gnome([H|T]) -> gnome([H], T).
If you know another functional language like SML or Haskell or the like, this will be easy enough to read. Even if you know some logic languages like Prolog this is simple enough to follow. If you only know imperative languages (unstructured, structured, OOP, etc.), however, this will be gibberish.
(Forth—concatenative)
defer precedes
defer exchange
: gnomesort ( a n)
swap >r 2 tuck 1- ( c2 n c1)
begin ( c2 n c1)
over over > ( c2 n c1 f)
while ( c2 n c1)
dup if ( c2 n c1)
dup dup 1- over over r@ precedes
if r@ exchange 1- else drop drop drop >r dup 1+ swap r> swap then
else drop >r dup 1+ swap r> swap then
repeat drop drop drop r> drop
;
:noname >r cells r@ + @ swap cells r> + @ swap < ; is precedes
:noname >r cells r@ + swap cells r> + over @ over @ swap rot ! swap ! ; is exchange
Although Forth is technically an imperative language, it is a very weird one with its stack discipline and unless you know it, or know related concatenative languages like Factor, this is going to be totally brain-damaging.
So in cases where you're unfamiliar with the paradigms involved: learn the paradigms. You should learn a new paradigm of programming every couple of years if you're a serious programmer, after all.