Cantor set: Difference between revisions
Content deleted Content added
m →Haskell :: Dual representation: (Tidying, applying Ormolu) |
|||
(66 intermediate revisions by 26 users not shown) | |||
Line 1:
{{task}}
;Task:
Draw a Cantor set.
See details at this Wikipedia webpage: [https://en.wikipedia.org/wiki/Cantor_set Cantor set]
<br><br>
=={{header|11l}}==
{{trans|Python}}
<
V HEIGHT = 5
Line 27 ⟶ 30:
L(i) 0 .< HEIGHT
V beg = WIDTH * i
print((lines[beg .< beg + WIDTH]).join(‘’))</
{{out}}
<pre>
Line 36 ⟶ 39:
* * * * * * * * * * * * * * * *
</pre>
=={{header|Action!}}==
<syntaxhighlight lang="action!">PROC FillRect(INT x,y,w,h)
INT i
FOR i=y TO y+h-1
DO
Plot(x,i)
DrawTo(x+w-1,i)
OD
RETURN
PROC DrawCantor(INT x0,y0,h,level)
INT x,y,i,j,w,w2,h2
w=1
FOR i=0 TO level-1
DO w==*3 OD
Color=1
y=y0
FOR i=0 TO level
DO
FillRect(x0,y,w,h)
y==+h*2
OD
Color=0
w2=1 h2=h*2
FOR i=0 TO level-1
DO
x=w2 y=(level-i)*(h*2)
WHILE x<w
DO
FillRect(x0+x,y0+y,w2,h2)
x==+w2*2
OD
w2==*3
h2==+h*2
OD
RETURN
PROC Main()
BYTE CH=$02FC,COLOR1=$02C5,COLOR2=$02C6
Graphics(8+16)
COLOR1=$0C
COLOR2=$02
DrawCantor(38,48,8,5)
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Cantor_set.png Screenshot from Atari 8-bit computer]
=={{header|Ada}}==
<
procedure Cantor_Set is
Line 61 ⟶ 118:
Ada.Text_IO.Put_Line (Image (L));
end loop;
end Cantor_Set;</
{{out}}
<pre>*********************************************************************************
Line 68 ⟶ 125:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|ALGOL 68}}==
<
# draw a Cantor Set using ASCII #
INT lines = 5; # number of lines for the set #
Line 96 ⟶ 152:
segment width OVERAB 3
OD
END</
{{out}}
<pre>
Line 105 ⟶ 161:
# # # # # # # # # # # # # # # #
</pre>
=={{header|ALGOL W}}==
Based on the Algol 68 sample.
<
% draw a Cantor Set using ASCII %
integer LINES; % number of lines for the set %
Line 141 ⟶ 196:
end for_l
end
end.</
{{out}}
<pre>
#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #
</pre>
=={{header|Amazing Hopper}}==
{{Trans|C}}
VERSION 1:
<syntaxhighlight lang="c">
#include <basico.h>
#define WIDTH 81
#define HEIGHT 5
#proto cantor(_X_,_Y_,_Z_)
algoritmo
decimales '0'
dimensionar(HEIGHT,WIDTH) matriz rellena("#",líneas)
_cantor(1, WIDTH, 2)
fijar separador 'NULO', imprimir( líneas, NL)
terminar
subrutinas
cantor(inicio, largo, índice)
seg=0
#( seg:=(int(largo/3))), no es cero?, entonces{
#basic{
líneas[índice:HEIGHT, (inicio+seg):((inicio+seg*2)-1)] = " ")
cantor( inicio, seg, índice+1 ) )
cantor( (inicio+(seg*2)), seg, índice+1 ) )
}
}
retornar
</syntaxhighlight>
{{out}}
<pre>
#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #
</pre>
{{Trans|Ruby}}
VERSION 2:
<syntaxhighlight lang="c">
#include <basico.h>
#define HEIGHT 5
algoritmo
decimales '0'
cantor="", j=0
iterar
i=0
cadenas 's,v'
iterar grupo ( ++i, #(i< (3^j)),\
#( v = occurs("1", dectobase(i,3)) ? " " : "#"; )\
#( s = s $ replicate(v, 3^(HEIGHT-j-1) )) )
#(cantor = cantor $ s $ NL)
mientras ' #(j<=HEIGHT); ++j '
imprimir(cantor)
terminar
</syntaxhighlight>
{{out}}
<pre>
Line 154 ⟶ 284:
Using composable library functions whenever possible, for better productivity:
<
-- cantor :: [String] -> [String]
Line 316 ⟶ 446:
set my text item delimiters to dlm
str
end unlines</
{{Out}}
<pre>█████████████████████████████████████████████████████████████████████████████████
Line 323 ⟶ 453:
███ ███ ███ ███ ███ ███ ███ ███
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █</pre>
=={{header|Arturo}}==
<syntaxhighlight lang="rebol">width: 81
height: 5
lines: array.of: height repeat `*` width
cantor: function [start length idx].export:[lines][
seg: length / 3
if seg = 0 -> return null
loop idx..dec height 'i [
loop (start + seg).. dec start + 2 * seg 'j
-> set lines\[i] j ` `
]
cantor start seg idx+1
cantor start + 2 * seg seg idx+1
]
cantor 0 width 1
loop lines 'line
-> print join line</syntaxhighlight>
{{out}}
<pre>*********************************************************************************
*************************** ***************************
********* ********* ********* *********
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|AWK}}==
<syntaxhighlight lang="awk">
# syntax: GAWK -f CANTOR_SET.AWK
# converted from C
Line 356 ⟶ 516:
cantor(start+seg*2,seg,indx+1)
}
</syntaxhighlight>
{{out}}
<pre>
Line 366 ⟶ 526:
</pre>
=={{header|
{{works with|QBasic}}
{{works with|GW-BASIC}}
{{works with|MSX BASIC}}
<syntaxhighlight lang="gwbasic">10 DEFINT A-Z
20 N = 4
30 W = 3^(N-1)
40 S = W
50 L$ = STRING$(W, "#")
60 PRINT L$
70 IF S = 1 THEN END
80 S = S\3
90 P = 1
100 IF P >= W-S GOTO 60
110 P = P+S
120 MID$(L$,P,S) = SPACE$(S)
130 P = P+S
140 GOTO 100</syntaxhighlight>
{{out}}
<pre>###########################
######### #########
### ### ### ###
# # # # # # # #</pre>
==={{header|BASIC256}}===
{{trans|FreeBASIC}}
<syntaxhighlight lang="vb">global ancho, alto, intervalo
ancho = 81 : alto = 5
dim intervalo(alto, ancho)
Line 401 ⟶ 584:
print
next i
end</syntaxhighlight>
==={{header|Chipmunk Basic}}===
{{trans|FreeBASIC}}
{{works with|Chipmunk Basic|3.6.4}}
<syntaxhighlight lang="qbasic">100 cls
110 ancho = 81
120 alto = 5
130 dim intervalo$(alto,ancho)
140 '
150 sub cantor()
160 for i = 0 to alto-1
170 for j = 0 to ancho-1
180 intervalo$(i,j) = chr$(254)
190 next j
200 next i
210 end sub
220 '
230 sub conjcantor(inicio,longitud,indice)
240 segmento = longitud/3
250 if segmento = 0 then exit sub
260 for i = indice to alto-1
270 for j = inicio+segmento to inicio+segmento*2-1
280 intervalo$(i,j) = chr$(32)
290 next j
300 next i
310 conjcantor(inicio,segmento,indice+1)
320 conjcantor(inicio+segmento*2,segmento,indice+1)
330 end sub
340 '
350 cantor()
360 conjcantor(0,ancho,1)
370 for i = 0 to alto-1
380 for j = 0 to ancho-1
390 print intervalo$(i,j);
400 next j
410 print
420 next i
430 end</syntaxhighlight>
==={{header|GW-BASIC}}===
{{works with|PC-BASIC|any}}
{{works with|BASICA}}
The [[#BASIC|BASIC]] solution works without any changes.
==={{header|MSX Basic}}===
{{works with|MSX BASIC|any}}
The [[#BASIC|BASIC]] solution works without any changes.
==={{header|QBasic}}===
{{trans|FreeBASIC}}
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">SUB Cantor
FOR i = 0 TO alto - 1
FOR j = 0 TO ancho - 1
intervalo$(i, j) = CHR$(254) '"#"
NEXT j
NEXT i
END SUB
SUB ConjCantor (inicio, longitud, indice)
segmento = INT(longitud / 3)
IF segmento = 0 THEN EXIT SUB
FOR i = indice TO alto - 1
FOR j = inicio + segmento TO inicio + segmento * 2 - 1
intervalo$(i, j) = CHR$(32) '" "
NEXT j
NEXT i
CALL ConjCantor(inicio, segmento, indice + 1)
CALL ConjCantor(inicio + segmento * 2, segmento, indice + 1)
END SUB
CONST ancho = 81
CONST alto = 5
DIM SHARED intervalo$(alto, ancho)
CLS
CALL Cantor
CALL ConjCantor(0, ancho, 1)
FOR i = 0 TO alto - 1
FOR j = 0 TO ancho - 1
PRINT intervalo$(i, j);
NEXT j
PRINT
NEXT i
END</syntaxhighlight>
==={{header|True BASIC}}===
{{trans|QBasic}}
<syntaxhighlight lang="qbasic">LET ancho = 81
LET alto = 5
DIM intervalo$(0,0)
MAT REDIM intervalo$(0 TO alto, 0 TO ancho)
SUB cantor
FOR i = 0 TO alto-1
FOR j = 0 TO ancho-1
LET intervalo$(i, j) = "#" !CHR$(254)
NEXT j
NEXT i
END SUB
SUB conjcantor (inicio,longitud,indice)
LET segmento = INT(longitud/3)
IF segmento = 0 THEN EXIT SUB
FOR i = indice TO alto-1
FOR j = inicio+segmento TO inicio+segmento*2-1
LET intervalo$(i, j) = CHR$(32) !" "
NEXT j
NEXT i
CALL conjcantor (inicio, segmento, indice+1)
CALL conjcantor (inicio+segmento*2, segmento, indice+1)
END SUB
CALL cantor
CALL conjcantor (0, ancho, 1)
FOR i = 0 TO alto-1
FOR j = 0 TO ancho-1
PRINT intervalo$(i, j);
NEXT j
PRINT
NEXT i
END</syntaxhighlight>
==={{header|Yabasic}}===
{{trans|FreeBASIC}}
<syntaxhighlight lang="vb">ancho = 81
alto = 5
dim intervalo$(alto, ancho)
Cantor()
ConjCantor(0, ancho, 1)
for i = 0 to alto - 1
for j = 0 to ancho - 1
print intervalo$(i, j);
next j
print
next i
end
sub Cantor()
for i = 0 to alto - 1
for j = 0 to ancho - 1
intervalo$(i, j) = chr$(254) //"#"
next j
next i
end sub
sub ConjCantor(inicio, longitud, indice)
segmento = longitud / 3
if segmento = 0 return
for i = indice to alto - 1
for j = inicio + segmento to inicio + segmento * 2 - 1
intervalo$(i, j) = " "
next j
next i
ConjCantor(inicio, segmento, indice + 1)
ConjCantor(inicio + segmento * 2, segmento, indice + 1)
end sub</syntaxhighlight>
=={{header|BQN}}==
<syntaxhighlight lang="bqn">Cantor ← {" •" ⊏˜ >⥊¨(¯1⊸⊏⊢¨¨⊢)1‿0‿1∧⌜⍟(↕𝕩)1}</syntaxhighlight>
{{out}}
<pre>
Cantor 5
┌─
╵"•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
••••••••••••••••••••••••••• •••••••••••••••••••••••••••
••••••••• ••••••••• ••••••••• •••••••••
••• ••• ••• ••• ••• ••• ••• •••
• • • • • • • • • • • • • • • •"
┘
</pre>
=={{header|C}}==
{{trans|Kotlin}}
<
#define WIDTH 81
Line 447 ⟶ 799:
print();
return 0;
}</
{{output}}
Line 457 ⟶ 809:
* * * * * * * * * * * * * * * *
</pre>
=={{header|C sharp|C#}}==
{{trans|Java}}
<
namespace CantorSet {
Line 498 ⟶ 849:
}
}
}</
{{out}}
<pre>*********************************************************************************
Line 505 ⟶ 856:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|C++}}==
{{trans|D}}
<
const int WIDTH = 81;
Line 543 ⟶ 893:
return 0;
}</
{{out}}
<pre>*********************************************************************************
Line 550 ⟶ 900:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|CLU}}==
<syntaxhighlight lang="clu">cantor = cluster is make
rep = null
ac = array[char]
aac = array[array[char]]
make = proc (width, height: int, ch: char) returns (string)
lines: aac := aac$fill_copy(0, height, ac$fill(0, width, ch))
cantor_step(lines, 0, width, 1)
s: stream := stream$create_output()
for line: ac in aac$elements(lines) do
stream$putl(s, string$ac2s(line))
end
return(stream$get_contents(s))
end make
cantor_step = proc (lines: aac, start, len, index: int)
seg: int := len / 3
if seg = 0 then return end
for i: int in int$from_to(index, aac$high(lines)) do
for j: int in int$from_to(start+seg, start+seg*2-1) do
lines[i][j] := ' '
end
end
cantor_step(lines, start, seg, index+1)
cantor_step(lines, start+seg*2, seg, index+1)
end cantor_step
end cantor
start_up = proc ()
po: stream := stream$primary_output()
cs: string := cantor$make(81, 5, '*')
stream$puts(po, cs)
end start_up</syntaxhighlight>
{{out}}
<pre>*********************************************************************************
*************************** ***************************
********* ********* ********* *********
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|COBOL}}==
<syntaxhighlight lang="cobol"> IDENTIFICATION DIVISION.
PROGRAM-ID. CANTOR.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SETTINGS.
03 NUM-LINES PIC 9 VALUE 5.
03 FILL-CHAR PIC X VALUE '#'.
01 VARIABLES.
03 CUR-LINE.
05 CHAR PIC X OCCURS 81 TIMES.
03 WIDTH PIC 99.
03 CUR-SIZE PIC 99.
03 POS PIC 99.
03 MAXPOS PIC 99.
03 NEXTPOS PIC 99.
03 I PIC 99.
PROCEDURE DIVISION.
BEGIN.
COMPUTE WIDTH = 3 ** (NUM-LINES - 1).
PERFORM INIT.
MOVE WIDTH TO CUR-SIZE.
DISPLAY CUR-LINE.
PERFORM DO-LINE UNTIL CUR-SIZE IS EQUAL TO 1.
STOP RUN.
INIT.
PERFORM INIT-CHAR VARYING I FROM 1 BY 1
UNTIL I IS GREATER THAN WIDTH.
INIT-CHAR.
MOVE FILL-CHAR TO CHAR(I).
DO-LINE.
DIVIDE 3 INTO CUR-SIZE.
MOVE 1 TO POS.
SUBTRACT CUR-SIZE FROM WIDTH GIVING MAXPOS.
PERFORM BLANK-REGIONS UNTIL POS IS GREATER THAN MAXPOS.
DISPLAY CUR-LINE.
BLANK-REGIONS.
ADD CUR-SIZE TO POS.
PERFORM BLANK-CHAR CUR-SIZE TIMES.
BLANK-CHAR.
MOVE SPACE TO CHAR(POS).
ADD 1 TO POS.</syntaxhighlight>
{{out}}
<pre>#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #</pre>
=={{header|D}}==
{{trans|C}}
<
enum WIDTH = 81;
Line 585 ⟶ 1,029:
writeln(lines[beg..beg+WIDTH]);
}
}</
{{out}}
<pre>*********************************************************************************
Line 594 ⟶ 1,038:
=={{header|Delphi}}==
{{Trans|Java}}
<syntaxhighlight lang="delphi">
program Cantor_set;
Line 644 ⟶ 1,088:
Readln;
end.
</syntaxhighlight>
{{out}}
Same result of Java
=={{header|EasyLang}}==
[https://easylang.online/show/#cod=S87PyS9SMDU15Sooyk9WSE7MKwHyKxQqFYqrFPQU9LgUFBQy00AcOwUDPUMQFwiKq4wVbEGC+grGUKHc/LJUsD5dkCxUsCg1uQSkDCGCZAFYITYpbQUjBS2wJJoiPS49LqgqAwULAwVDAwMuAA== Run it]
<syntaxhighlight lang=text>
color 555
proc cantor x y sz . .
if sz > 0.1
sz3 = sz / 3
move x y - sz3
rect sz sz3
cantor x y - sz3 sz3
cantor x + 2 * sz3 y - sz3 sz3
.
.
cantor 0 80 100
</syntaxhighlight>
=={{header|Elixir}}==
<syntaxhighlight lang="elixir">
defmodule Cantor do
@pos "█"
@neg " "
def run(lines) do
Enum.map(0..lines, fn line ->
segment_size = 3 ** (lines - line - 1)
chars = (3 ** line)
Enum.map(0..chars, fn char ->
char
|> Integer.digits(3)
|> Enum.any?(fn x -> x === 1 end)
|> case do
true -> @neg
false -> @pos
end
end)
|> Enum.reduce([], fn el, acc -> duplicate_char(acc, el, segment_size) end)
|> Enum.join()
|> String.trim_trailing()
end)
|> Enum.filter(fn line -> line !== "" end)
end
def duplicate_char(acc, el, segment_size) when segment_size >= 1, do: acc ++ [String.duplicate(el, segment_size)]
def duplicate_char(acc, _el, segment_size) when segment_size < 1, do: acc
end
Cantor.run(5) |> IO.inspect()
</syntaxhighlight>
{{out}}
<pre>["█████████████████████████████████████████████████████████████████████████████████",
"███████████████████████████ ███████████████████████████",
"█████████ █████████ █████████ █████████",
"███ ███ ███ ███ ███ ███ ███ ███",
"█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █"]</pre>
=={{header|EMal}}==
<syntaxhighlight lang="emal">
int WIDTH = 81
int HEIGHT = 5
List lines = text[].with(HEIGHT) # a list with HEIGHT empty texts
for each int i in range(0, HEIGHT) do lines[i] = text("█", WIDTH) end
fun cantor = void by int start, int len, int index
int seg = len / 3
if seg == 0 do return end
for int i = index; i < HEIGHT; i++
for int j = start + seg; j < start + seg * 2; j++
lines[i][j] = " "
end
end
cantor(start, seg, index + 1)
cantor(start + seg * 2, seg, index + 1)
end
cantor(0, WIDTH, 1)
for each text line in lines do writeLine(line) end
</syntaxhighlight>
{{out}}
<pre>
█████████████████████████████████████████████████████████████████████████████████
███████████████████████████ ███████████████████████████
█████████ █████████ █████████ █████████
███ ███ ███ ███ ███ ███ ███ ███
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
</pre>
=={{header|Excel}}==
===LAMBDA===
Binding names to the following lambda expressions in the Name Manager of the Excel WorkBook:
(See [https://www.microsoft.com/en-us/research/blog/lambda-the-ultimatae-excel-worksheet-function/ LAMBDA: The ultimate Excel worksheet function])
{{Works with|Office 365 betas 2021}}
<syntaxhighlight lang="lisp">CANTOR
=LAMBDA(n,
APPLYN(n)(
LAMBDA(grid,
APPENDROWS(grid)(
CANTOROW(
LASTROW(grid)
)
)
)
)({0,1})
)
CANTOROW
=LAMBDA(xys,
LET(
nCols, COLUMNS(xys),
IF(2 > nCols,
xys,
IF(3 < nCols,
APPENDCOLS(
CANTORSLICES(TAKECOLS(2)(xys))
)(
CANTOROW(DROPCOLS(2)(xys))
),
CANTORSLICES(TAKECOLS(2)(xys))
)
)
)
)
CANTORSLICES
=LAMBDA(ab,
LET(
a, INDEX(ab, 1),
b, INDEX(ab, 2),
third, (b - a) / 3,
CHOOSE({1,2,3,4}, a, a + third, b - third, b)
)
)
SHOWCANTOR
=LAMBDA(grid,
LET(
leaves, LASTROW(grid),
leafWidth, INDEX(leaves, 1, 2) - INDEX(leaves, 1, 1),
leafCount, 1 / leafWidth,
SHOWCANTROWS(leafCount)(grid)
)
)
SHOWCANTROWS
=LAMBDA(leafCount,
LAMBDA(grid,
LET(
xs, FILTERP(
LAMBDA(x, NOT(ISNA(x)))
)(
HEADCOL(grid)
),
runLengths, LAMBDA(x,
CEILING.MATH(leafCount * x))(
SUBTRACT(TAILROW(xs))(INITROW(xs)
)
),
iCols, SEQUENCE(1, COLUMNS(runLengths)),
CONCAT(
REPT(
IF(ISEVEN(iCols), " ", "█"),
runLengths
)
) & IF(1 < ROWS(grid),
CHAR(10) & SHOWCANTROWS(leafCount)(
TAILCOL(grid)
),
""
)
)
)
)</syntaxhighlight>
and also assuming the following generic bindings in the Name Manager for the WorkBook:
<syntaxhighlight lang="lisp">APPENDCOLS
=LAMBDA(xs,
LAMBDA(ys,
LET(
nx, COLUMNS(xs),
ny, COLUMNS(ys),
colIndexes, SEQUENCE(1, nx + ny),
rowIndexes, SEQUENCE(MAX(ROWS(xs), ROWS(ys))),
IFERROR(
IF(nx < colIndexes,
INDEX(ys, rowIndexes, colIndexes - nx),
INDEX(xs, rowIndexes, colIndexes)
),
NA()
)
)
)
)
APPENDROWS
=LAMBDA(xs,
LAMBDA(ys,
LET(
nx, ROWS(xs),
rowIndexes, SEQUENCE(nx + ROWS(ys)),
colIndexes, SEQUENCE(
1,
MAX(COLUMNS(xs), COLUMNS(ys))
),
IFERROR(
IF(rowIndexes <= nx,
INDEX(xs, rowIndexes, colIndexes),
INDEX(ys, rowIndexes - nx, colIndexes)
),
NA()
)
)
)
)
APPLYN
=LAMBDA(n,
LAMBDA(f,
LAMBDA(x,
IF(0 < n,
APPLYN(n - 1)(f)(
f(x)
),
x
)
)
)
)
DROPCOLS
=LAMBDA(n,
LAMBDA(xs,
INDEX(
xs,
SEQUENCE(ROWS(xs), 1),
SEQUENCE(1, (COLUMNS(xs) - n), 1 + n, 1)
)
)
)
FILTERP
=LAMBDA(p,
LAMBDA(xs,
FILTER(xs, p(xs))
)
)
HEADCOL
=LAMBDA(xs,
LET(REM, "The first item of each column in xs",
INDEX(xs, 1, SEQUENCE(1, COLUMNS(xs)))
)
)
INITROW
=LAMBDA(xs,
INDEX(
xs,
SEQUENCE(
1,
COLUMNS(xs) - 1,
1, 1
)
)
)
LASTROW
=LAMBDA(xs,
INDEX(
xs,
ROWS(xs),
SEQUENCE(1, COLUMNS(xs), 1, 1)
)
)
SUBTRACT
=LAMBDA(a,
LAMBDA(b, a - b)
)
TAILCOL
=LAMBDA(cols,
LET(REM, "The tail of each column in the grid.",
INDEX(
cols,
SEQUENCE(ROWS(cols) - 1, 1, 2, 1),
SEQUENCE(1, COLUMNS(cols))
)
)
)
TAILROW
=LAMBDA(xs,
LET(REM,"The tail of each row in the grid",
n, COLUMNS(xs) - 1,
IF(0 < n,
INDEX(
xs,
SEQUENCE(ROWS(xs), 1, 1, 1),
SEQUENCE(1, n, 2, 1)
),
NA()
)
)
)
TAKECOLS
=LAMBDA(n,
LAMBDA(xs,
INDEX(
xs,
SEQUENCE(ROWS(xs)),
SEQUENCE(1, n)
)
)
)</syntaxhighlight>
{{Out}}
As a string, with the format of the cell set to a mono-spaced font, and with ''Format > Cells > Alignment > Wrap text = True'', to allow for the display of Excel's (platform - independent) CHAR(10) line breaks:
{| class="wikitable"
|-
|||style="text-align:right; font-family:serif; font-style:italic; font-size:120%;"|fx
! colspan="2" style="text-align:left; vertical-align: bottom; font-family:Arial, Helvetica, sans-serif !important;"|=SHOWCANTOR(CANTOR(1))
|- style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff;"
|
| A
| B
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 1
| style="text-align:right; " | SHOWCANTOR(CANTOR(0))
| style="text-align:left; font-weight:bold" | <syntaxhighlight lang="text">█</syntaxhighlight>
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 2
| style="text-align:right; " | SHOWCANTOR(CANTOR(1))
| style="text-align:left; background-color:#cbcefb;" | <syntaxhighlight lang="text">███
█ █</syntaxhighlight>
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 3
| style="text-align:right; " | SHOWCANTOR(CANTOR(2))
| style="text-align:left; font-weight:bold" | <syntaxhighlight lang="text">█████████
███ ███
█ █ █ █</syntaxhighlight>
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 4
| style="text-align:right; " | SHOWCANTOR(CANTOR(3))
| style="text-align:left; font-weight:bold" | <syntaxhighlight lang="text">███████████████████████████
█████████ █████████
███ ███ ███ ███
█ █ █ █ █ █ █ █</syntaxhighlight>
|}
The diagrams above are drawn from the array of underlying fractions defined by CANTOR(n).
(The expression in B2 below defines the values which populate the grid B2:Q5)
The enclosing application of the built-in IFNA function maps undefined numeric cells in that grid (with the Excel value #N/A) to empty strings, for a more readable display.
(The number format for the numeric cells is set to ''Fraction > Up to three digits.'')
{| class="wikitable"
|-
|||style="text-align:right; font-family:serif; font-style:italic; font-size:120%;"|fx
! colspan="17" style="text-align:left; vertical-align: bottom; font-family:Arial, Helvetica, sans-serif !important;"|=IFNA(CANTOR(3), "")
|- style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff;"
|
| A
| B
| C
| D
| E
| F
| G
| H
| I
| J
| K
| L
| M
| N
| O
| P
| Q
|-
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|-
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 2
| style="text-align:right; font-weight:bold" | Unit range
| style="text-align:left; background-color:#cbcefb" | 0
| style="text-align:left" | 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|-
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 3
| style="text-align:right; font-weight:bold" | Cantor 1
| style="text-align:left" | 0
| style="text-align:left" | 1/3
| style="text-align:left" | 2/3
| style="text-align:left" | 1
|
|
|
|
|
|
|
|
|
|
|
|
|-
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 4
| style="text-align:right; font-weight:bold" | Cantor 2
| style="text-align:left" | 0
| style="text-align:left" | 1/9
| style="text-align:left" | 2/9
| style="text-align:left" | 1/3
| style="text-align:left" | 2/3
| style="text-align:left" | 7/9
| style="text-align:left" | 8/9
| style="text-align:left" | 1
|
|
|
|
|
|
|
|
|-
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 5
| style="text-align:right; font-weight:bold" | Cantor 3
| style="text-align:left" | 0
| style="text-align:left" | 1/27
| style="text-align:left" | 2/27
| style="text-align:left" | 1/9
| style="text-align:left" | 2/9
| style="text-align:left" | 7/27
| style="text-align:left" | 8/27
| style="text-align:left" | 1/3
| style="text-align:left" | 2/3
| style="text-align:left" | 19/27
| style="text-align:left" | 20/27
| style="text-align:left" | 7/9
| style="text-align:left" | 8/9
| style="text-align:left" | 25/27
| style="text-align:left" | 26/27
| style="text-align:left" | 1
|}
=={{header|Factor}}==
<
sequences.repeating ;
IN: rosetta-code.cantor-set
Line 672 ⟶ 1,626:
concat print ;
depth <iota> [ print-cantor ] each</
{{out}}
<pre>
Line 681 ⟶ 1,635:
# # # # # # # # # # # # # # # #
</pre>
=={{header|Forth}}==
Where is says <code>[email protected]</code> it should say <code>c@</code>, but I'm not keen on writing it as <code>c&#64;</code> in the actual code.
<
4 \ iterations
Line 709 ⟶ 1,662:
: go print BEGIN step done? UNTIL ;
go bye</
Output:
<pre>#################################################################################
Line 716 ⟶ 1,669:
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #</pre>
=={{header|FreeBASIC}}==
<
Const ancho = 81
Const alto = 5
Line 755 ⟶ 1,707:
Next i
End
</syntaxhighlight>
{{out}}
<pre>
Line 764 ⟶ 1,716:
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
</pre>
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
_window = 1
_width = 81
_height = 5
window _window, @"FutureBasic Cantor Set", ( 0, 0, 695, 100 )
WindowSetBackgroundColor( _window, fn ColorWhite )
text @"Menlo", 14.0, fn ColorRed
begin globals
CFStringRef gInterval( _height, _width )
end globals
local fn Init
NSInteger i, j
for i = 0 to _height - 1
for j = 0 to _width - 1
gInterval( i, j ) = @"◼︎"
next
next
end fn
local fn CantorSet( start as NSInteger, length as NSInteger, index as NSInteger )
NSInteger i, j, segment = length / 3
if segment == 0 then exit fn
for i = index to _height - 1
for j = start + segment to start + segment * 2 - 1
gInterval( i, j ) = @" "
next
next
fn CantorSet( start, segment, index + 1 )
fn CantorSet( start + segment * 2, segment, index + 1 )
end fn
NSInteger i, j
fn Init
fn CantorSet ( 0, _width, 1 )
for i = 0 to _height - 1
for j = 0 to _width - 1
print gInterval( i, j );
next
print
next
HandleEvents
</syntaxhighlight>
{{output}}
[[File:FutureBasic Cantor Set.png]]
=={{header|Fōrmulæ}}==
{{FormulaeEntry|page=https://formulae.org/?script=examples/The_Cantor_set}}
'''Solution'''
Strictly speaking, a visualization of the perfect Cantor set is impossible, it consists of a infinite set of isolated points in the interval [0, 1]. The most we can do is drawing the early steps of its construction.
Several ways of visualization of the Cantor set are shown.
'''Preliminaries'''
Let us start with a definition of the points that define the central points of the intervals of the Cantos set on any step:
[[File:Fōrmulæ - Cantor set 01.png]]
[[File:Fōrmulæ - Cantor set 02.png]]
[[File:Fōrmulæ - Cantor set 03.png]]
The followign function defines the segments on each step:
[[File:Fōrmulæ - Cantor set 04.png]]
[[File:Fōrmulæ - Cantor set 05.png]]
[[File:Fōrmulæ - Cantor set 06.png]]
=== Plotting the central points ===
[[File:Fōrmulæ - Cantor set 07.png]]
[[File:Fōrmulæ - Cantor set 08.png]]
=== Common method ===
[[File:Fōrmulæ - Cantor set 09.png]]
[[File:Fōrmulæ - Cantor set 10.png]]
[[File:Fōrmulæ - Cantor set 11.png]]
=== Cantor dust ===
[[File:Fōrmulæ - Cantor set 12.png]]
[[File:Fōrmulæ - Cantor set 13.png]]
[[File:Fōrmulæ - Cantor set 14.png]]
=== [https://en.wikipedia.org/wiki/Knaster%E2%80%93Kuratowski_fan Knaster–Kuratowski fan or "Cantor teepee"] ===
[[File:Fōrmulæ - Cantor set 15.png]]
[[File:Fōrmulæ - Cantor set 16.png]]
[[File:Fōrmulæ - Cantor set 17.png]]
The following forms of visualization are taken from [https://en.wikipedia.org/wiki/Point-set_topology point-set topology]. They are not intended as forms of visualization of the Cantor set, instead, these structures make use of the Cantor set.
=== [https://en.wikipedia.org/wiki/Indecomposable_continuum Brouwer–Janiszewski–Knaster continuum, or "the bucket handle"] ===
[[File:Fōrmulæ - Cantor set 18.png]]
[[File:Fōrmulæ - Cantor set 19.png]]
[[File:Fōrmulæ - Cantor set 20.png]]
=== "Double Knaster" ===
[[File:Fōrmulæ - Cantor set 21.png]]
[[File:Fōrmulæ - Cantor set 22.png]]
[[File:Fōrmulæ - Cantor set 23.png]]
=={{header|Go}}==
{{trans|Kotlin}}
<
import "fmt"
Line 805 ⟶ 1,891:
fmt.Println(string(line[:]))
}
}</
{{out}}
Line 815 ⟶ 1,901:
* * * * * * * * * * * * * * * *
</pre>
=={{header|Groovy}}==
{{trans|Java}}
<
private static final int WIDTH = 81
private static final int HEIGHT = 5
Line 853 ⟶ 1,938:
}
}
}</
{{out}}
<pre>*********************************************************************************
Line 860 ⟶ 1,945:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|Haskell}}==
===Interval bars===
{{Trans|Python}} (Functional version)
<syntaxhighlight lang="haskell">-------------------------- CANTOR ------------------------
cantor :: [(Bool, Int)] -> [(Bool, Int)]
cantor =
where
go (bln, n)
in [(True, m), (False, m), (True, m)]
| otherwise = [(bln, n)]
--------------------------- TEST -------------------------
main :: IO ()
main = putStrLn $ cantorLines 5
------------------------- DISPLAY ------------------------
cantorLines :: Int -> String
cantorLines n =
unlines $
showCantor
<$> take n (iterate cantor [(True, 3 ^ pred n)])
showCantor :: [(Bool, Int)] -> String
showCantor =
where
c True = '*'
c False = ' '</syntaxhighlight>
{{Out}}
<pre>*********************************************************************************
Line 891 ⟶ 1,984:
Or, using strings for the model as well as the display:
<syntaxhighlight lang="haskell">-------------------------- CANTOR ------------------------
cantor :: [String] -> [String]
cantor = (go =<<)
where
Line 900 ⟶ 1,995:
m = quot (length x) 3
block = take m x
--------------------------- TEST -------------------------
main :: IO ()
main = putStrLn $ cantorLines 5
------------------------- DISPLAY ------------------------
cantorLines :: Int -> String
cantorLines =
unlines . (concat <$>)
. ( take
<*> ( iterate cantor
. return
. flip replicate '█'
. (3 ^)
. pred
)
)</syntaxhighlight>
{{Out}}
<pre>█████████████████████████████████████████████████████████████████████████████████
Line 916 ⟶ 2,023:
===Dual representation===
Intervals as fraction pairs, and intervals as graphic bars:
<syntaxhighlight lang
import Data.Bifunctor (bimap)
import Data.List (intercalate, mapAccumL, maximumBy)
import Data.Ratio (Ratio, denominator, numerator, (%))
Line 922 ⟶ 2,031:
cantor :: (Rational, Rational) -> [[(Rational, Rational)]]
cantor = iterate (
where
go (x, y) = [(x, x + r), (y - r, y)]
Line 931 ⟶ 2,040:
main :: IO ()
main =
( ( (>>)
. putStrLn
. unlines
. fmap intervalRatios
)
<*> (putStrLn . intervalBars)
)
$ take 4 $ cantor (0, 1)
------------------------- DISPLAY ------------------------
Line 959 ⟶ 2,073:
('(' :) . (<> ")")
. intercalate ") ("
. fmap
(uncurry ((<>) . (<> ", ")) . join bimap showRatio)
showRatio :: Rational -> String
Line 968 ⟶ 2,081:
go x
| 1 /= x = '/' : show x
| otherwise = []</
{{Out}}
<pre>(0, 1)
Line 979 ⟶ 2,092:
███ ███ ███ ███
█ █ █ █ █ █ █ █</pre>
=={{header|IS-BASIC}}==
<
110 GRAPHICS HIRES 2
120 SET PALETTE BLACK,WHITE
Line 991 ⟶ 2,103:
180 CALL CANTOR(X+2*L/3,Y-HEIGHT,L/3,HEIGHT)
190 END IF
200 END DEF</
=={{header|J}}==
The argument to the cantor_dust monad is an integer that describes the depth of the dust. Shown here are results for cantor_dust 2 and for cantor_dust 3 . It works by checking for 1 digits in the base 3 representation of the coordinates. These background coordinates are plotted with # character using ASCII art. 1j1 #"1 expands the lines to improve aspect ratio on character cell (console) display. }:"1 curtails the extra space character line by line. < draws a pretty box.
<syntaxhighlight lang="j">
odometer =: [: (4 $. $.) $&1
Line 1,004 ⟶ 2,115:
< (}:"1) 1j1 #"1 '#' (([: <"1 [: ;/"1 (#~ 1 e."1 [: (,/"2) 3 3&#:)) i)}a
)
</syntaxhighlight>
<pre>
Line 1,053 ⟶ 2,164:
</pre>
With an `x' argument cantor_dust generalizes to higher dimensions. Try 3 cantor_dust 2
<syntaxhighlight lang="j">
cantor_dust =: 2&$: :(dyad define)
shape =. x # 3 ^ y
Line 1,060 ⟶ 2,171:
< (}:"1) 1j1 #"1 '#' (([: <"1 [: ;/"1 (#~ 1 e."1 [: (,/"2) 3 3&#:)) i)} a
)
</syntaxhighlight>
=={{header|Java}}==
{{trans|Kotlin}}
<
private static final int WIDTH = 81;
private static final int HEIGHT = 5;
Line 1,100 ⟶ 2,210:
}
}
</syntaxhighlight>
{{out}}
<pre>*********************************************************************************
Line 1,107 ⟶ 2,217:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|JavaScript}}==
===Cantor: (Bool, Int) pairs===
{{Trans|Python}} (Functional version)
{{Trans|Haskell}}
<
// -------------- CANTOR BOOL-INT PAIRS --------------
[true, x]
];
];
};
// ---------------------- TEST -----------------------
// main :: IO ()
const main = ()
cantorLines(5);
//
//
// showCantor :: [(Bool, Int)] -> String
const showCantor = xs =>
xs.map(
([bln, n]) => (
bln ? (
"*"
) : " "
).repeat(n)
)
.join("");
// ---------------- GENERIC FUNCTIONS ----------------
// iterate :: (a -> a) -> a -> Gen [a]
function*
let v =
v = f(v);
}
};
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take =
// The first n elements of a list,
// string of characters, or stream.
xs => "GeneratorFunction" !== xs
.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
// MAIN ---
return main();
})();</
{{Out}}
<pre>*********************************************************************************
Line 1,214 ⟶ 2,316:
* * * * * * * * * * * * * * * *</pre>
===Cantor: Strings===
Using strings for the model as well as the display:
{{Trans|Haskell}}
<
// ----------------- CANTOR STRINGS ------------------
// cantor :: [String] -> [String]
Line 1,237 ⟶ 2,329:
const
m = Math.floor(s.length / 3),
blocks = take(m
return "█" ===
[blocks, " ".repeat(m), blocks]
) : [s];
};
return xs.flatMap(go);
};
//
const main = () =>
showCantor(5);
// --------------------- DISPLAY ---------------------
const showCantor = n =>
take(n)(
iterate(cantor)([
"█".repeat(3 ** (n - 1))
])
)
.map(x => x.join(""))
.join("\n");
// ---------------- GENERIC FUNCTIONS ----------------
// iterate :: (a -> a) -> a -> Gen [a]
function*
let v =
v = f(v);
}
};
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take =
// The first n elements of a list,
// string of characters, or stream.
xs => "GeneratorFunction" !== xs
.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
// MAIN ---
return main();
})();</
{{Out}}
<pre>█████████████████████████████████████████████████████████████████████████████████
Line 1,301 ⟶ 2,398:
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █</pre>
===
{{Trans|Haskell}}
{{Trans|Python}}
Cantor ternary intervals rendered both as lists of
In the case of languages like Javascript which lack a built-in Ratio type, or standard Fraction/Ratio library, rendering stages of the set elaboration as lists of fraction pairs may take more work than rendering them as graphic lines.
<
// -------------- CANTOR RATIONAL PAIRS --------------
// cantor :: [(Rational, Rational)] ->
// [(Rational, Rational)]
const cantor = xs => {
const go =
const [r1, r2] =
const third = ratioDiv(ratioMinus(r2
return [
Tuple(r1
Tuple(ratioMinus(r2
];
};
return xs.flatMap(go);
};
// ---------------------- TEST -----------------------
// main :: IO ()
const main = () => {
const
xs = take(4)(
iterate(cantor)([Tuple(0)(1)])
);
return [
`${unlines(xs.map(intervalRatios))}\n`,
intervalBars(xs)
]
.join("\n\n");
};
// --------------------- DISPLAY ---------------------
// intervalRatios :: [(Rational, Rational)] -> String
const intervalRatios = xs => {
const go =
)
return `(${xs.map(go).join(") (")})`;
};
// intervalBars :: [[(Rational, Rational)]] -> String
const intervalBars =
const go = w => xs =>
const [wx, wy] = Array.from(ab).map(
r => ratioMult(w
)
);
return
replicateString(
)(" ") + replicateString(
floor(ratioMinus(wy)(wx))
)("█")
);
}
const d =
return unlines(rs.map(
go(Ratio(d)(1))
));
};
//
// Ratio :: Integral a => a -> a -> Ratio a
const Ratio = a => b => {
const go = (x, y) =>
0 !== y ? (() => {
const d = gcd(x)(y);
return {
type: "Ratio",
// numerator
"n": Math.trunc(x / d),
// denominator
"d": Math.trunc(y / d)
};
})() : undefined;
return go(a * signum(b), abs(b));
};
// Tuple (,) :: a -> b -> (a, b)
const Tuple =
length: 2
});
// abs :: Num -> Num
const abs =
// Absolute value of a given number
// without the sign.
x => 0 > x ? (
-x
) : x;
//
return _gcd(Math.abs(x), Math.abs(y));
},
c = gcde(Boolean(eps) ? (
eps
) : (1 / 10000), 1, n);
return Ratio(
Math.floor(n / c)
)(
Math.floor(1 / c)
);
};
// floor :: Num -> Int
Line 1,403 ⟶ 2,555:
const
nr = (
properFraction
) : properFracRatio
)(x),
n = nr[0];
return 0 > nr[1] ? n - 1 : n;
};
// fst :: (a, b) -> a
const fst =
// First member of a pair.
ab[0];
// gcd :: Integral a => a -> a -> a
const gcd = x =>
y => {
const zero = x.constructor(0);
const go = (a, b) =>
zero === b ? (
a
) : go(b, a % b);
return go(abs(x), abs(y));
};
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// iterate :: (a -> a) -> a -> Gen [a]
function*
let v =
while (true) {
yield v;
v = f(v);
}
};
// last :: [a] -> a
const last = xs =>
0 < xs.length ? (
xs.slice(-1)[0]
) : null;
// lcm :: Int -> Int -> Int
const lcm =
// The smallest positive integer divisible
// without remainder by both x and y.
y => (x === 0 || y === 0) ? (
0
) : Math.abs(Math.floor(x / gcd(x)(y)) * y);
//
// acc -> [x] -> (acc, [y])
const mapAccumL = f =>
// A tuple of an accumulation and a list
// obtained by a combined map and fold,
// with accumulation from left to right.
acc => xs => [...xs].reduce(
(a, x) => {
const ab = f(a[0])(x);
return [ab[0], a[1].concat(ab[1])];
},
[acc, []]
);
// maximum :: Ord a => [a] -> a
const maximum = xs => (
(a, y) => y > a ? (
y
) : a, ys[0]
)
) : undefined
)(xs);
// properFracRatio :: Ratio -> (Int, Ratio)
const properFracRatio = nd => {
const [q, r] = Array.from(quotRem(nd.n
return Tuple(q)(Ratio(r)(nd.d));
};
// properFraction :: Real -> (Int, Real)
const properFraction = n => {
const i = Math.floor(n) + (n < 0 ? 1 : 0);
return Tuple(i)(n - i);
};
// quotRem ::
const quotRem =
// The quotient, tupled with the remainder.
n => Tuple(
Math.trunc(m / n)
)(
m % n
);
// ratioDiv :: Rational -> Rational -> Rational
const ratioDiv =
const [r1, r2] =
return Ratio(r1.n * r2.d)(
r1.d * r2.n
);
};
// ratioMinus :: Rational -> Rational -> Rational
const ratioMinus =
const [r1, r2] =
const d = lcm(r1.d
return Ratio(
(r1.n * (d / r1.d)) - (r2.n * (d / r2.d))
)(d);
};
// ratioMult :: Rational -> Rational -> Rational
const ratioMult =
const [r1, r2] =
return Ratio(r1.n * r2.n)(
);
};
// ratioPlus :: Rational -> Rational -> Rational
const ratioPlus = n1 =>
n2 => {
const [r1, r2] = [n1, n2].map(rational);
const d = lcm(r1.d)(r2.d);
return Ratio(
(r1.n * (d / r1.d)) + (
r2.n * (d / r2.d)
)
)(d);
};
// rational :: Num a => a -> Rational
const rational = x =>
isNaN(x) ? x :
Ratio(x)(1)
) : approxRatio(undefined)(x);
// replicateString :: Int -> String -> String
const replicateString =
s => s.repeat(n);
// showRatio :: Ratio -> String
const showRatio = r =>
r.toString()
) : r.n.toString() + (
1 !== r.d ? (
) :
);
// signum :: Num -> Num
const signum = n =>
// | Sign of a number.
n.constructor(
0 > n ? (
-1
) : (
0 < n ? 1 : 0
)
);
// snd :: (a, b) -> b
const snd =
// Second member of a pair.
ab[1];
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take =
// The first n elements of a list,
// string of characters, or stream.
xs => "GeneratorFunction" !== xs
.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
// unlines :: [String] -> String
const unlines = xs =>
// A single string formed by the intercalation
// of a list of strings with the newline character.
xs.join("\n");
// MAIN ---
return main();
})();</
{{Out}}
<pre>(0, 1)
Line 1,581 ⟶ 2,803:
███ ███ ███ ███
█ █ █ █ █ █ █ █</pre>
=={{header|jq}}==
<
def cantor($w; $h):
def init: [range(0; $h) | [range(0; $w) | "*"]];
Line 1,600 ⟶ 2,821:
cantor($width; $height)
| pp</
{{out}}
With the above in a file, cantor.jq, the following incantation
yields the same output as shown e.g. under `awk`, `julia`, etc.
jq -nr --argjson width 81 --argjson height 5 -f cantor.jq
=={{header|Julia}}==
{{trans|AWK}}
<
const height = 5
Line 1,629 ⟶ 2,848:
print(Char(lines[i, j]), j == width ? "\n" : "")
end
</
<pre>
#################################################################################
Line 1,637 ⟶ 2,856:
# # # # # # # # # # # # # # # #
</pre>
=={{header|Kotlin}}==
Simple terminal drawing.
<
const val WIDTH = 81
Line 1,660 ⟶ 2,878:
cantor(0, WIDTH, 1)
lines.forEach { println(it) }
}</
{{output}}
Line 1,670 ⟶ 2,888:
* * * * * * * * * * * * * * * *
</pre>
=={{header|Lua}}==
{{trans|python}}
<
local HEIGHT = 5
local lines = {}
Line 1,718 ⟶ 2,935:
end
print()
end</
{{out}}
<pre>*********************************************************************************
Line 1,725 ⟶ 2,942:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">Graphics[MeshPrimitives[CantorMesh[#],1]/.{x_}:>{x,-0.05#}&/@Range[5],ImageSize->600]</syntaxhighlight>
{{out}}
A graphic of a Cantor set is shown
=={{header|MiniScript}}==
<syntaxhighlight lang="miniscript">
cantorSet = function(start, length, depth)
if depth == 0 then return [[start, start+length - 1]]
newLen = length / 3
leftInterval = cantorSet(start, newLen, depth - 1)
rightInterval = cantorSet(start + 2 * newLen, newLen, depth - 1)
return leftInterval + rightInterval
end function
for depth in range(0, 4)
output =[" "] * 81
segments = cantorSet(1, 81,depth)
for segment in segments
for x in range(segment[0] - 1, segment[1]-1)
output[x] = "#"
end for
end for
print output.join("")
end for
</syntaxhighlight>
{{out}}
<pre>
#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #
</pre>
=={{header|Modula-2}}==
{{trans|Kotlin}}
<
FROM Terminal IMPORT Write,WriteLn,ReadChar;
Line 1,779 ⟶ 3,033:
ReadChar;
END Cantor.</
=={{header|Nim}}==
{{trans|Kotlin}}
<
const
Line 1,804 ⟶ 3,057:
cantor(0, Width, 1)
for line in lines:
echo line</
{{Out}}
Line 1,812 ⟶ 3,065:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|Objeck}}==
{{trans|Java}}
<syntaxhighlight lang="objeck">class CantorSet {
WIDTH : static : Int;
HEIGHT : static : Int;
lines : static : Char[,];
function : Init() ~ Nil {
WIDTH := 81;
HEIGHT := 5;
lines := Char->New[HEIGHT, WIDTH];
each(i : HEIGHT) {
each(j : WIDTH) {
lines[i,j] := '*';
};
};
}
function : Cantor(start : Int, len : Int, index : Int) ~ Nil {
seg : Int := len / 3;
if(seg = 0) {
return;
};
for(i := index; i < HEIGHT; i += 1;) {
for(j := start + seg; j < start + seg * 2; j += 1;) {
lines[i,j] := ' ';
};
};
Cantor(start, seg, index + 1);
Cantor(start + seg * 2, seg, index + 1);
}
function : Main(args : String[]) ~ Nil {
Init();
Cantor(0, WIDTH, 1);
each(i : HEIGHT) {
each(j : WIDTH) {
lines[i,j]->Print();
};
""->PrintLine();
};
}
}</syntaxhighlight>
{{Output}}
<pre>
*********************************************************************************
*************************** ***************************
********* ********* ********* *********
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *
</pre>
=={{header|Perl}}==
{{trans|Raku}}
<
use feature 'say';
Line 1,842 ⟶ 3,151:
}
say for cantor(5);</
{{Out}}
Line 1,851 ⟶ 3,160:
# # # # # # # # # # # # # # # #</pre>
===regex version===
<syntaxhighlight lang="perl">#!/usr/bin/perl -l
use strict; # https://rosettacode.org/wiki/Cantor_set
use warnings;
$_ = '#' x 81;
1 while print, s/(#+)\1\1/ $1 . $1 =~ tr!#! !r . $1 /ge;</syntaxhighlight>
{{out}}
<pre>
#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #
</pre>
=={{header|Phix}}==
Based on Algol 68, but even simpler, shorter, and sweeter!
<!--<
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
Line 1,870 ⟶ 3,196:
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<!--</
{{out}}
<pre>
Line 1,879 ⟶ 3,205:
# # # # # # # # # # # # # # # #
</pre>
=={{header|Phixmonti}}==
<
5 >ps
Line 1,901 ⟶ 3,226:
cps
line ?
endfor</
Other solution
<
5 >ps
Line 1,919 ⟶ 3,244:
endfor
endfor
line ?</
{{out}}
<pre>#################################################################################
Line 1,928 ⟶ 3,253:
=== Press any key to exit ===</pre>
=={{header|PL/M}}==
{{works with|8080 PL/M Compiler}} ... under CP/M (or an emulator)
<syntaxhighlight lang="plm">
100H: /* DRAW A CANTOR SET USING ASCII */
/* BDOS SYSTEM CALL AND I/O ROUTINES */
BDOS: PROCEDURE( F, A ); DECLARE F BYTE, A ADDRESS; GOTO 5; END;
PR$CHAR: PROCEDURE( C ); DECLARE C BYTE; CALL BDOS( 2, C ); END;
PR$NL: PROCEDURE; CALL PR$CHAR( 0DH ); CALL PR$CHAR( 0AH ); END;
/* DRAW A CANTOR SET */
DECLARE LINES LITERALLY '4';
DECLARE WIDTH LITERALLY '27'; /* MUST BE 3**(LINES-1) */
DECLARE LINE (WIDTH)BYTE;
DECLARE ( I, L, C, W, S, SEGMENTS ) BYTE;
DO I = 0 TO LAST( LINE );
LINE( I ) = 023H;
CALL PR$CHAR( LINE( I ) );
END;
CALL PR$NL;
W = WIDTH;
SEGMENTS = 1;
DO L = 2 TO LINES;
W = W / 3;
SEGMENTS = SEGMENTS * 3;
C = 0;
DO S = 1 TO SEGMENTS;
DO I = 1 TO W;
IF NOT S THEN LINE( C ) = ' '; /* EVEN SEGMENT - BLANK IT */
CALL PR$CHAR( LINE( C ) );
C = C + 1;
END;
END;
CALL PR$NL;
END;
EOF
</syntaxhighlight>
{{out}}
<pre>
###########################
######### #########
### ### ### ###
# # # # # # # #
</pre>
=={{header|Processing}}==
<syntaxhighlight lang="java">
//Aamrun, 1st July 2022
void cantorSet(int x1,int y1,int x2,int y2,int strWt,int gap,int n){
strokeWeight(strWt);
line(x1,y1,x2,y2);
if(n>0){
cantorSet(x1,gap + y1,(2*x1+x2)/3,gap + (2*y1+y2)/3,strWt,gap,n-1);
cantorSet((2*x2+x1)/3,gap + (2*y2+y1)/3,x2,gap + y2,strWt,gap,n-1);
}
}
void setup(){
size(1000,1000);
cantorSet(100,10,900,10,1,10,5);
}
</syntaxhighlight>
=={{header|Python}}==
===Imperative===
<
HEIGHT = 5
Line 1,954 ⟶ 3,346:
for i in xrange(HEIGHT):
beg = WIDTH * i
print ''.join(lines[beg : beg+WIDTH])</
{{out}}
<pre>*********************************************************************************
Line 1,964 ⟶ 3,356:
Separating ''(Bool, Int)'' model from ''String'' display:
{{Works with|Python|3.7}}
<
from functools import (reduce)
Line 2,037 ⟶ 3,429:
# MAIN ---
if __name__ == '__main__':
main()</
{{Out}}
<pre>
Line 2,050 ⟶ 3,442:
{{Trans|Haskell}}
{{Works with|Python|3.7}}
<
from itertools import (chain, islice)
Line 2,120 ⟶ 3,512:
# MAIN ---
if __name__ == '__main__':
main()</
{{Out}}
<pre>█████████████████████████████████████████████████████████████████████████████████
Line 2,130 ⟶ 3,522:
===Dual representations – fractional and graphic===
{{Works with|Python|3.7}}
<
representations of its output.
'''
Line 2,255 ⟶ 3,647:
# MAIN ---
if __name__ == '__main__':
main()</
{{Out}}
<pre>(0, 1)
Line 2,266 ⟶ 3,658:
███ ███ ███ ███
█ █ █ █ █ █ █ █</pre>
=={{header|QB64}}==
{{trans|FreeBASIC}}
Line 2,272 ⟶ 3,663:
Note: Other languages will need to zero out the a() array. In QB64 all arrays are initialized to zero at program start.
<
Dim Shared As Integer sw, sh, wide, high
Line 2,309 ⟶ 3,700:
Next
Next
End Sub</
=={{header|Quackery}}==
===Using an L-System===
(Described at [[L-system#Quackery]].)
<syntaxhighlight lang="quackery"> [ $ "" swap witheach
[ nested quackery join ] ] is expand ( $ --> $ )
[ $ "ABA" ] is A ( $ --> $ )
[ $ "BBB" ] is B ( $ --> $ )
[ char A = iff
[ char q ] else space
swap of echo$ ] is draw ( n c --> $ )
81 $ "A"
5 times
[ dup witheach
[ dip over draw ]
cr
i if
[ expand
dip [ 3 / ] ] ]
2drop
</syntaxhighlight>
{{out}}
<pre>qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqq qqqqqqqqq qqqqqqqqq qqqqqqqqq
qqq qqq qqq qqq qqq qqq qqq qqq
q q q q q q q q q q q q q q q q
</pre>
=={{header|R}}==
[https://creativecommons.org/licenses/by-nc-sa/4.0 Attribution-NonCommercial-ShareAlike 4.0 International, CC BY-NC-SA 4.0] to neonira@gmail.com
<syntaxhighlight lang="r">
cantorSet <- function() {
depth <- 6L
cs <- vector('list', depth)
cs[[1L]] <- c(0, 1)
for(k in seq_len(depth)) {
cs[[k + 1L]] <- unlist(sapply(seq_len(length(cs[[k]]) / 2L), function(j) {
p <- cs[[k]][2L] / 3
h <- 2L * (j - 1L)
c(
cs[[k]][h + 1L] + c(0, p),
cs[[k]][h + 2L] - c(p, 0)
)
}, simplify = FALSE))
}
cs
}
cantorSetGraph <- function() {
cs <- cantorSet()
u <- unlist(cs)
df <- data.frame(
x_start = u[seq_along(u) %% 2L == 1L],
x_end = u[seq_along(u) %% 2L == 0L],
depth = unlist(lapply(cs, function(e) {
l <- length(e)
n <- 0
while(l > 1) {
n <- n + 1L
l <- l / 2
}
rep(n, length(e) / 2)
}))
)
require(ggplot2)
g <- ggplot(df, aes_string(x = 'x_start', y = 'depth')) +
geom_segment(aes_string(xend = 'x_end', yend = 'depth', size = 3)) +
scale_y_continuous(trans = "reverse") +
theme(
axis.title = element_blank(),
axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
legend.position = 'none',
aspect.ratio = 1/5
)
list(graph = g, data = df, set = cs)
}
</syntaxhighlight>
{{out}}
Currently, RosettaCode does not seem to accept image upload anymore.
So, you will have to run the program under R or RStudio IDE to get the diagram result.
=={{header|Racket}}==
{{trans|Kotlin}}
<
;; {trans|Kotlin}}
Line 2,338 ⟶ 3,825:
(module+ main
(for-each displayln (Cantor_set)))
</syntaxhighlight>
{{out}}
<pre>*********************************************************************************
Line 2,346 ⟶ 3,833:
* * * * * * * * * * * * * * * *
</pre>
=={{header|Raku}}==
(formerly Perl 6)
{{trans|Kotlin}}
<syntaxhighlight lang="raku"
my $width = 3 ** ($height - 1);
Line 2,370 ⟶ 3,856:
}
.say for cantor(5);</
{{Out}}
Line 2,378 ⟶ 3,864:
███ ███ ███ ███ ███ ███ ███ ███
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █</pre>
=={{header|REXX}}==
<
w= linesize() /*obtain the width of the display term.*/
if w==0 then w= 81 /*Can't obtain width? Use the default.*/
Line 2,395 ⟶ 3,880:
say $ /*display a line of the Cantor Set. */
#= # % 3 /*the part (thirds) to be blanked out. */
end /*j*/ /*stick a fork in it, we're all done. */</
This REXX program makes use of '''linesize''' REXX program (or BIF) which is used to determine the screen width (or linesize) of the terminal (console).
Line 2,421 ⟶ 3,906:
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
</pre>
=={{header|Ring}}==
<
# Project : Cantor set
Line 2,475 ⟶ 3,959:
cantor(x+floor(lens*2/3),y,floor(lens/3))
ok
</syntaxhighlight>
Output image:
[https://www.dropbox.com/s/ap7c3301i0syh4e/CantorSet.jpg?dl=0 Cantor set]
=={{header|Ruby}}==
This works by numbering the segments (starting with 0) in base 3. Print whitespace if this number contains the digit 1; a black square otherwise.
<
(0..lines).each do |exp|
Line 2,489 ⟶ 3,972:
puts chars.map{ |c| c * seg_size }.join
end
</syntaxhighlight>
{{out}}
<pre>█████████████████████████████████████████████████████████████████████████████████
Line 2,498 ⟶ 3,981:
</pre>
=={{header|Rust}}==
<
use convert_base::Convert;
use std::fmt;
Line 2,566 ⟶ 4,048:
}
</syntaxhighlight>
{{out}}
<pre>
Line 2,577 ⟶ 4,059:
</pre>
=={{header|Scala}}==
===Imperative Programming (Q&D)===
<
val (width, height) = (81, 5)
Line 2,601 ⟶ 4,082:
cantor(0, width, 1)
lines.foreach(l => println(l.mkString))
}</
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/QrqaHeu/0 (JavaScript)]
or by [https://scastie.scala-lang.org/4JTi1zXzRq6H4yUlAYNTSw Scastie (JVM)].
===Functional Programming (Recommended)===
<
val (width, height) = (81, 5)
Line 2,637 ⟶ 4,118:
output.map(l => (0 to width).map(pos => if (l contains pos) '*' else ' ').mkString)
.mkString("\n"))
}</
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/szUjPWO/7 (JavaScript)]
or by [https://scastie.scala-lang.org/ZaNUtEOcStuBfJImOnEz5Q Scastie (JVM)].
=={{header|Sidef}}==
{{trans|Raku}}
<
var width = 3**(height - 1)
var lines = height.of { "\N{FULL BLOCK}" * width }
Line 2,663 ⟶ 4,143:
}
cantor(5).each { .say }</
{{out}}
<pre>
Line 2,672 ⟶ 4,152:
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
</pre>
=={{header|Smalltalk}}==
{{works with|GNU Smalltalk}}
Smalltalk represents Intervals' start and stop values as Fraction, so precision is kept for quilte a while.
<
| intervals |
Line 2,743 ⟶ 4,222:
]
TestCantor iterations: 4.</
Output:
<pre>#################################################################################
Line 2,750 ⟶ 4,229:
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #</pre>
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">const (
width = 81
height = 5
)
fn cantor(mut lines [][]u8, start int, len int, index int) {
seg := len / 3
if seg == 0 {
return
}
for i in index.. height {
for j in start + seg..start + 2 * seg {
lines[i][j] = ' '[0]
}
}
cantor(mut lines, start, seg, index + 1)
cantor(mut lines, start + seg * 2, seg, index + 1)
}
fn main() {
mut lines := [][]u8{len:height, init: []u8{len:width, init:'*'[0]}}
cantor(mut lines, 0, width, 1)
for line in lines {
println(line.bytestr())
}
}</syntaxhighlight>
{{out}}
<pre>
*********************************************************************************
*************************** ***************************
********* ********* ********* *********
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *
</pre>
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<
Const WIDTH = 81
Line 2,792 ⟶ 4,308:
End Sub
End Module</
{{out}}
<pre>*********************************************************************************
Line 2,799 ⟶ 4,315:
*** *** *** *** *** *** *** ***
* * * * * * * * * * * * * * * *</pre>
=={{header|VTL-2}}==
<syntaxhighlight lang="vtl2">
1010 L=4
1020 I=1
1030 X=1
1040 I=I+1
1050 X=X*3
1060 #=I<L*1040
2010 I=0
2020 :I)=35
2030 $=:I)
2040 I=I+1
2050 #=I<X*2020
2060 ?=""
2070 W=X
2080 G=1
2090 W=W/3
2100 G=G*3
2110 S=1
2120 C=0
2130 I=1
2140 #=S/2*0+%=1*2160
2150 :C)=32
2160 $=:C)
2170 C=C+1
2180 I=I+1
2190 #=W>I*2140
2200 S=S+1
2210 #=C<X*2130
2220 ?=""
2230 L=L-1
2240 #=1<L*2090
</syntaxhighlight>
{{out}}
<pre>
###########################
######### #########
### ### ### ###
# # # # # # # #
</pre>
=={{header|Wren}}==
{{trans|Kotlin}}
<
var height = 5
Line 2,820 ⟶ 4,377:
cantor.call(0, width, 1)
for (i in 0...height) System.print(lines[i].join())</
{{out}}
Line 2,831 ⟶ 4,388:
</pre>
=={{header|XPL0}}==
<syntaxhighlight lang="xpl0">proc Cantor(N, LineSeg, Len); \Delete middle third of LineSeg
int N; char LineSeg; int Len, Third, I;
[if N>0 and Len>1 then
[Third:= Len/3;
for I:= Third, 2*Third-1 do LineSeg(I):= ^ ;
Cantor(N-1, LineSeg, Third);
Cantor(N-1, LineSeg+2*Third, Third);
];
];
char LineSeg, N;
[LineSeg:=
"#################################################################################
";
for N:= 0 to 4 do
[Cantor(N, LineSeg, 81);
Text(0, LineSeg);
];
]</syntaxhighlight>
{{out}}
<pre>
#################################################################################
########################### ###########################
######### ######### ######### #########
### ### ### ### ### ### ### ###
# # # # # # # # # # # # # # # #
</pre>
=={{header|zkl}}==
<
var lines=HEIGHT.pump(List,List.createLong(WIDTH,"\U2588;").copy); // full block
Line 2,844 ⟶ 4,430:
}(0,WIDTH,1);
lines.pump(Console.println,"concat");</
{{out}}
<pre>
|