Learn A New Language
February 21, 2012
We’ve done this before, and had some fun, so we’ll do it again.
There are hundreds, probably thousands, of programming language. Some are general-purpose, others are intended for a limited domain. Some are useful, most get in your way. Some are just weird. We programmers frequently have to learn a new language, or re-learn an old one, or adapt to improvements from the vendor.
A good way to learn a new language is to write in the new language a familiar program from an old language with which you are experienced. Many people have written that they use the exercises at Programming Praxis as a way to get started with a new language.
Your task is to write a program that solves the Programming Praxis exercise of your choice in a programming language in which you are not proficient. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
I’m a little surprised (and humbled) to be the first to post an answer to this challenge. Back when I was in College, I learned about Touring Completeness. At the time, I didn’t give it much thought until about 5 or so years ago, I stumbled across a programming language called BrainF**k (BF for short). I didn’t care for the name, but the concept was truly fascinating. The language simulates a one tape Touring Machine using only 8 instructions which manipulate one pointer and tape data under that pointer. In theory, this is all that’s needed to write any program in the world. When I saw this 5 years ago, I wrote a Hello World to prove the concept to myself, and didn’t give it another thought … until now.
I decided to write a program which would output the HailStone sequence defined by the previous exercise, using BF. Well, almost. I actually used Procedural BF (pBrain for short) which slightly extends the instruction sets to add capability to define and call functions in 3 additional instructions. You can read more about pBrain at http://www.parkscomputing.com/code/pbrain/. To simplify my work, I made a couple of assumptions. The user input of the starting number must be between 01 and 99, always entered as two characters with a leading zero. The output will always be displayed as a 3 digit number with leading zeros. This touring machine has an 8-bit memory, so no single number within the sequence must exceed 255.
Without further ado, here is my Touring Machine (with procedural enhancements) implementation of a HailStone sequence. There are plenty of comments in the code. Frankly, I needed them to keep myself sane. Of course, the nice side effect of the comments is that everyone should be able to understand what is going on. As an example, when run with an input like 07, the output is 007 022 011 034 017 052 026 013 040 020 010 005 016 008 004 002 001
/**************************************/
/* HAILSTONE SEQUENCE PROGRAM */
/* in pBrain */
/**************************************/
// Memory map
// 0: ASCII_MSB
// 1: ASCII_LSB
// 2: User_Input
// 3: R1
// 4: R2
// 5: R3
// 6: R4
// 7: R5
// 8: R6
// 9: R7
// A: R8
// B: R9
// C: R10
// D: R11
// E: R12
// F: R13
// 10: R14
// 11: R15
// 12: R16
/**************************************/
/* Function 1 – Convert ASCII(n) to integer N by subtracting 6*8=ASCII(0) */
/* Input: @(-1) – the ASCII value of n */
/* Output: @(-1) – the integer value N */
/* Local: @(+1) and @(+2) */
+(
// loop 6*8 times, decrementing @(-1)
>++++++++[
>++++++[
<<<-
>>>-
]<-
]
// Exit with calling register set back to zero
<-
)
/*************************************/
/* Function 2 – Divide A/B */
/* Input: @(-2) – Divident A */
/* Input: @(-1) – Divisor B */
/* Local: @(+1) – Copy of dividend */
/* Local: @(+2) – Copy of dividend */
/* Local: @(+3) – Remainder */
/* Local: @(+4) – Copy of divisor */
/* Local: @(+5) – Quotient */
/* Local: @(+6) – Zero */
/* Local: @(+7) – Zero */
/* Output: @(+5) – Quotient */
/* Output: @(+3) – Remainder */
+(
// make sure the local variables are zero’d out
>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<
// copy dividend to @(+1) and @(+2) destroying @(-2)
<<[>>>+>+<<<<-]
// copy divisor to @(+4) destroying @(-1)
>[>>>>>+<<<<<-]
// point to first copy of dividend and start division
>>
[
>+>+>-[>>>]
<[[>+<-]>>+>]
<<<<<-
]
// Exit with calling register set back to zero
<–
)
/**************************************/
/* Function 3 – display integer 0-255 as ASCII */
/* Input: @(-1) – the ASCII value of n */
/* Local: @(+1), @(+2), @(+3) – ASCII result */
/* Local: @(+4) through @(+13) – used in division */
+(
// Make sure that we start with a clean slate for internal output registers
[-]>[-]>[-]>[-]
// Figure out the 100’s digit.
// Copy number to divident
<<<<[>+>>>>+<<<<<-]>[<+>-]
// Set divisor to 10*10=100
>>>>>>++++++++++[>++++++++++[<<+>>-]<-]<
// Call division function
>++:
// Process results of division
>>>>>
[
// Copy quotient into MSB
<<<<<<<<+
// subtract quotient*100 from number
>++++++++++ [>++++++++++ [<<<<<<->>>>>>-]<- ]
>>>>>>>-
]
// Convert to ascii by adding 6*8=48
<<<<<<[-]<[-]++++++ [ >++++++++ [<<+>>-]<- ]
// Figure out the 10’s digit
>>>[-]<[-]<[-]
// Copy number to divident
<<<<<<[>+>>>>+<<<<<-]>[<+>-]
// Set divisor to 2*5=10
>>>>>>++[>+++++[<<+>>-]<-]<
// Call division function
>++:
// Process results of division
>>>>>
[
// Copy quotient into Middle digit
<<<<<<<<<+
// subtract quotient*10 from number
>>++ [ >+++++ [<<<<<<->>>>>>-]<- ]
>>>>>>>-
]
// Convert to ascii by adding 6*8=48
<<<<<<[-]<[-]++++++ [ >++++++++ [<<<+>>>-]<- ]
// Copy the remainder (1’s digit) into LSB
>>>>>[<<<<<<<<+>>>>>>>>-]
// Convert to ascii by adding 6*8=48
<<<<[-]<[-]++++++ [ >++++++++ [<<<<+>>>>-]<- ]
// Display the number with a space after it
<.<.<.[-]>[-]>[-]< ++++ [ >++++++++ [<<+>>-]<- ] <.
// exit with calling register set to zero
<[-]
)
/**************************************/
/**************** MAIN ****************/
// Get user input for MSB and LSB stored in @ASCII_MSB and @ASCII_LSB
,>,
// Move @ASCII_MSB to R1
<[>>>+<<<-]
// Call Func1 from R2, using R1 as arg1, R3 and R4 as local vars
>>>>+:
// Move @ASCII_LSB to R2
<<<[>>>+<<<-]
// Call Func1 from R3, using R2 as arg1, R4 and R5 as local vars
>>>>+:
// @User_Input = R1*10 + R2, destroying R1, R2 contents
<<[<++++++++++>-]
>[<<+>>-]
// Copy @User_input to R1 using R2
// Display R1 by calling Func3 from R2, using R3-R16 as local vars
<< [>+>+<<-] >>[<<+>>-] +++:
// While @User_Input != 1
<<-
[
// Copy @User_Input to R1, using R2, set R2 to two
+>[-]<[>+>+<<-]>>[<<+>>-]++
// Call Func2 from R3, using R1 and R2 as arg1 and arg2, and R4-R10 as local vars
>[-]++:
// Test R6 (remainder) to see if it’s Zero, use R7 for starting else clause
>>>>[-]+<
[
// Remainder is not Zero, must have been an odd number
// @user_Input = 3*@User_input + 1
<<<<<[-]<[>+++<-]>+[<+>-]
// Set remainder and R7 to zero to skip else clause
>>>>>>-<-
]
>
[
// Remainder is Zero, must have been an even number
// Copy R8 (quotient) to @User_input
<<<<<<<[-]>>>>>>>>[<<<<<<<<+>>>>>>>>-]<[-]
]
// Copy @User_input to R1 using R2
// Display R1 by calling Func3 from R2, using R3-R16 as local vars
<<<<<<< [>+>+<<-] >>[<<+>>-] +++:
// Test if @User_Input == 1
<<-
]
Ran into SmallBasic yesterday: a world without scope is pretty interesting…
‘ Reference:
‘ Cormen, Thomas H.; Leiserson, Charles E.; and Rivest, Ronald L
‘ Introduction to Algorithms
‘ The MIT Press and McGraw-Hill Book Company, 1990
‘ ISBN 0-262-03141-8 (MIT Press), ISBN 0-07-013143-0 (McGraw-Hill)
arraySize = 40
maxValue = 99
TextWindow.WriteLine(“Begin execution”)
PopulateArray()
TextWindow.WriteLine(“Before sorting:”)
ShowArray()
BuildHeap()
ShowHeap()
HeapSort()
TextWindow.WriteLine(“After sorting:”)
ShowArray()
Validate()
‘ Ensure no dupes are in the array
Sub PopulateArray
For i = 1 To maxValue
selected[i] = 0
EndFor
For i = 1 To arraySize
random = Math.GetRandomNumber(maxValue)
While(selected[random] > 0)
random = Math.GetRandomNumber(maxValue)
EndWhile
selected[random] = 1
a[i] = random
EndFor
EndSub
‘ Output 4 lines of 10 each, with leading 0 if necessary
Sub ShowArray
For index = 1 To arraySize
If (a[index] 0 And heap[j] 1) Then
parent = 1
While(parent*2 <= heapsize)
left = parent * 2
right = left + 1
swapIndex = parent
If (heap[left] < heap[swapIndex]) Then
swapIndex = left
EndIf
If (heap[right] < heap[swapIndex] And right a[j]) then
TextWindow.BackgroundColor = “Red”
TextWindow.WriteLine(“OH NO!”)
Endif
Endfor
Endfor
EndSub
Still very, very new to Clojure. I thought I would do lazy primes using leftist heap, + the leftist heap exercise, which is therefore quite a lot for (laziness, data structures, etc.)
First the left heap:
Then the lazy primes with O’Neil’s algorithm:
Then to try it out: