User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 3:21 pm

@hippy,

I noticed you were also interested in the IUP extension module. Did you have a chance to download and install it?

hippy
Posts: 5125
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: ScriptBasic

Thu May 23, 2019 3:25 pm

Not yet. I have some other plates I need to keep spinning.

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 4:17 pm

I wonder what happened to Heater? He seems to have gone silent.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Thu May 23, 2019 4:28 pm

Still around.

Actually I got diverted into playing with Scheme for a bit. After being reminded of it during the fibo challenge and then wondering if there is a small Scheme engine I could embed in my RISC V project. Just for something different. Tiny Scheme looks possible. Or Chibi Scheme.

So I was going to ask you, what is the Lisp/Scheme thing you made a ScriptBasic module for?

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 4:30 pm

hippy wrote:
Thu May 23, 2019 3:25 pm
Not yet. I have some other plates I need to keep spinning.
I'm looking forward to your GPIO extension module. It will give ScriptBasic more of a RPi identity. It seems getting a GPIO interface built is only half the battle. Talking to the many sensors is another level.

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 5:03 pm

Heater wrote: So I was going to ask you, what is the Lisp/Scheme thing you made a ScriptBasic module for?
The TinyScheme extension module allows the ScriptBasic programmer to load and call Scheme functions and return their result for further processing in ScriptBasic.

If ScriptBasic was a RPi, the GPIO interface is what extension modules are all about.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Thu May 23, 2019 5:27 pm

Ah, thanks.

Chibbi Scheme seems to be somewhat newer than TinyScheme supporting the latest Scheme standards with the same intention to be an embedded scripting language.

I know nothing much of Scheme yet, or it's standards, so It comes down to what is easiest to use in an actual embedded system.

Or, maybe, that is just a silly idea anyway...

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 5:45 pm

Scheme is an interesting language (self defining) I hope to learn more about. Having it as an extension to SB makes learning it a lot easier.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Thu May 23, 2019 6:18 pm

Scheme certainly is interesting. The R7 Scheme standard document is a great read: https://small.r7rs.org/attachment/r7rs.pdf

Currently Scheme gives me headache.

It suffers from the same problem as "BASIC". Everyone and his dog has their own version with various tweaks and extensions done in different ways. I found that even getting the simplest examples running is an exercise in frustration as one has to "fix" it for ones chosen Scheme variant which is invariably different to the example's author's variant.

And when does one stop being "bracket blinded"?

I like the idea of Chibi Scheme, it's built for embedding, it supports that standard above. Created by a guy who is on the standard committee. It's claimed to be much faster than TinyScheme. Maybe you would like to have a look at it.

I have been amusing myself by following the Berkely CS 61A undergrad CS course by Brian Harvey in 2010: https://www.youtube.com/playlist?list=P ... NKG1b-LFY9

It's amazing, Harvey introduces programming with Scheme and in no time at all is into some serious CS stuff. I saw a later version of that course that was using Java, it took most of the time just to get the students to understand how to do anything at all in Java, let alone the CS concepts the course is supposed to be about.

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 6:45 pm

I'm taking on Scheme in baby steps until I see a pattern to its design.

That Scheme class reminds me of a nut shell game con explaining how easy I can be fooled. :D

On the other hand the Lua introduction video I posted earlier is something I would like to model a ScriptBasic introduction after.
Last edited by ScriptBasic on Thu May 23, 2019 7:37 pm, edited 1 time in total.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Thu May 23, 2019 7:37 pm

ScriptBasic,

That is perhaps the frustrating thing. The pattern to the design of Scheme is amazingly simple.

Everything is a function call with parameters wrapped brackets:

Code: Select all

(someFuntion param1 parm3 param3)
Simple things like arithmetic operators are functions the same way:

Code: Select all

(+ 5 9)
(* x y)
That hyper simple syntax is enough to express anything. Other language constructs like defining your own functions and variables with "define" or "let", building control features like "if" etc are all just functions and parameters in the same way.

That very simplicity is what makes it so hard to get used to!

It's like the total lack of syntactic baggage in Forth. Makes it hard to see what is going on, everything looks the same! It's a whole lot more powerfully expressive than Forth mind.

As Brian Harvey says to his students halfway through the first lecture "Now you know 90% of the Scheme language"

Here is a nice Fibonacci in Chibi Scheme I found:

Code: Select all

(define fibo (lambda (n)
    (let ((alpha (/  (+ 1 (sqrt 5)) 2) )
           (beta (/  (- 1 (sqrt 5)) 2) ))

      (round (- (* (/ 1 (sqrt 5)) (expt alpha n))
                (* (/ 1 (sqrt 5)) (expt beta n)))))))

(display (fibo 70))
(newline)
When standing back and looking at it, ignoring all the brackets, it looks pretty much like it would look in other languages. It's a function, with a parameter, that has a couple of local variables and returns an expression. Easy !

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 7:42 pm

Scheme is like trying to understand the Brainf*ck language.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Thu May 23, 2019 8:02 pm

Ouch, I would not go that far. At least you can give meaningful names to things is Scheme.

I always thought that languages that supported infix operator notation in expressions were the way to go. "4 * 7 + 3" or "(x / (y * 9) is what we all get used to in high school. All that post fix notation of Forth is just confusing, " 3 4 7 * +" or "x y 9 * /". As is the prefix notation of Scheme.

But.... Brian Harvey points out this not the correct way to think about it. Even in high school maths we use all those forms. Factorials are post fix, "x!". Square roots and such have their operator wrap all the way around the operand. There is noting consistent. So why be disturbed by Schemes choice of notation?

Of course major features of Scheme are the fact that functions are data. They can be passed to other functions, returned by functions and so on. Then there is the concept of closures. Or the fact that implementing iteration with recursion is quite acceptable All of this is very alien if one is used to only languages like BASIC and C.

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Thu May 23, 2019 8:21 pm

ScriptBasic functions are like data as well and can be used as replacements for variables. ScriptBasic let's you use them in expressions even if the result is a numeric string.

Code: Select all

i = "16"
FOR x = LEFT(i,1) TO RIGHT(i,1) STEP LEN(i)
  PRINT x,"\n"
NEXT
[email protected]:~/sb/examples/test$ scriba func.sb
1
3
5
[email protected]:~/sb/examples/test$

jahboater
Posts: 4185
Joined: Wed Feb 04, 2015 6:38 pm

Re: ScriptBasic

Fri May 24, 2019 1:31 am

ScriptBasic wrote:
Thu May 23, 2019 8:21 pm
ScriptBasic functions are like data as well and can be used as replacements for variables. ScriptBasic let's you use them in expressions even if the result is a numeric string.
You mean like "x + sin(0.5) + y + sqrt(2)" say?
Yes, all programming languages can do that (all sensible ones anyway), that's what a function is.

I think Heater means like in C where you pass the address of a function around, or perhaps have an array of functions which you can index. Different mechanism in Scala of course.

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 24, 2019 2:03 am

Something like this?

Code: Select all

SUB One
  PRINT "One\n"
END SUB

SUB Two
  PRINT "Two\n"
END SUB

SUB Three
  PRINT "Three\n"
END SUB


f[1] = ADDRESS(One())
f[2] = ADDRESS(Two())
f[3] = ADDRESS(Three())

FOR i = 1 TO 3
  ICALL(f[i])
NEXT
[email protected]:~/sb/examples/test$ scriba addr.sb
One
Two
Three
[email protected]:~/sb/examples/test$

FYI This is post 666 :twisted:

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 24, 2019 4:34 am

Here is the gpio extension module as I left it waiting for your input.

Code: Select all

/* GPIO Extension Module
UXLIBS: -lc
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "c_gpio.h"
#include "../../basext.h"

#define BCM2708_PERI_BASE_DEFAULT   0x20000000
#define BCM2709_PERI_BASE_DEFAULT   0x3f000000
#define GPIO_BASE_OFFSET            0x200000
#define FSEL_OFFSET                 0   // 0x0000
#define SET_OFFSET                  7   // 0x001c / 4
#define CLR_OFFSET                  10  // 0x0028 / 4
#define PINLEVEL_OFFSET             13  // 0x0034 / 4
#define EVENT_DETECT_OFFSET         16  // 0x0040 / 4
#define RISING_ED_OFFSET            19  // 0x004c / 4
#define FALLING_ED_OFFSET           22  // 0x0058 / 4
#define HIGH_DETECT_OFFSET          25  // 0x0064 / 4
#define LOW_DETECT_OFFSET           28  // 0x0070 / 4
#define PULLUPDN_OFFSET             37  // 0x0094 / 4
#define PULLUPDNCLK_OFFSET          38  // 0x0098 / 4

#define PAGE_SIZE  (4*1024)
#define BLOCK_SIZE (4*1024)

static volatile uint32_t *gpio_map;

static void short_wait(void)
{
    int i;

    for (i=0; i<150; i++) {    // wait 150 cycles
        asm volatile("nop");
    }
}

static void clear_event_detect(int gpio)
{
    int offset = EVENT_DETECT_OFFSET + (gpio/32);
    int shift = (gpio%32);

    *(gpio_map+offset) |= (1 << shift);
    short_wait();
    *(gpio_map+offset) = 0;
}

static void set_pullupdn(int gpio, int pud)
{
    int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
    int shift = (gpio%32);

    if (pud == PUD_DOWN)
        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
    else if (pud == PUD_UP)
        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
    else  // pud == PUD_OFF
        *(gpio_map+PULLUPDN_OFFSET) &= ~3;

    short_wait();
    *(gpio_map+clk_offset) = 1 << shift;
    short_wait();
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    *(gpio_map+clk_offset) = 0;
}

/**************************
 Extension Module Functions
**************************/

typedef struct _ModuleObject {
  void *HandleArray;
}ModuleObject,*pModuleObject;


besVERSION_NEGOTIATE
  return (int)INTERFACE_VERSION;
besEND


besSUB_START
  pModuleObject p;

  besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
  if( besMODULEPOINTER == NULL )return 0;

  p = (pModuleObject)besMODULEPOINTER;
  return 0;
besEND


besSUB_FINISH
  pModuleObject p;

  p = (pModuleObject)besMODULEPOINTER;
  if( p == NULL )return 0;
  return 0;
besEND



/***************
 GPIO Functions
***************/


besFUNCTION(sb_short_wait)
    int i;

    for (i=0; i<150; i++) {    // wait 150 cycles
        asm volatile("nop");
    }
besEND



besFUNCTION(sb_setup)
    int mem_fd;
    uint8_t *gpio_mem;
    uint32_t peri_base = 0;
    uint32_t gpio_base;
    unsigned char buf[4];
    FILE *fp;
    char buffer[1024];
    char hardware[1024];
    int found = 0;

    // try /dev/gpiomem first - this does not require root privs
    if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0)
    {
        if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) {
            besRETURN_LONG(SETUP_MMAP_FAIL);
        } else {
            besRETURN_LONG(SETUP_OK);
        }
    }
    // revert to /dev/mem method - requires root

    // determine peri_base
    if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
        // get peri base from device tree
        fseek(fp, 4, SEEK_SET);
        if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
            peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
        }
        fclose(fp);
    } else {
        // guess peri base based on /proc/cpuinfo hardware field
        if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
            besRETURN_LONG(SETUP_CPUINFO_FAIL);

        while(!feof(fp) && !found && fgets(buffer, sizeof(buffer), fp)) {
            sscanf(buffer, "Hardware	: %s", hardware);
            if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) {
                // pi 1 hardware
                peri_base = BCM2708_PERI_BASE_DEFAULT;
                found = 1;
            } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) {
                // pi 2 hardware
                peri_base = BCM2709_PERI_BASE_DEFAULT;
                found = 1;
            }
        }
        fclose(fp);
        if (!found)
            besRETURN_LONG(SETUP_NOT_RPI_FAIL);
    }

    if (!peri_base)
        besRETURN_LONG(SETUP_NOT_RPI_FAIL);
    gpio_base = peri_base + GPIO_BASE_OFFSET;

    // mmap the GPIO memory registers
    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
        besRETURN_LONG(SETUP_DEVMEM_FAIL);

    if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
        besRETURN_LONG(SETUP_MALLOC_FAIL);

    if ((uint32_t)gpio_mem % PAGE_SIZE)
        gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);

    if ((gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base)) == MAP_FAILED)
        besRETURN_LONG(SETUP_MMAP_FAIL);

    besRETURN_LONG(SETUP_OK);
besEND


besFUNCTION(sb_clear_event_detect)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset = EVENT_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  *(gpio_map+offset) |= (1 << shift);
  short_wait();
  *(gpio_map+offset) = 0;
besEND


besFUNCTION(sb_eventdetected)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset, value, bit;
  offset = EVENT_DETECT_OFFSET + (gpio/32);
  bit = (1 << (gpio%32));
  value = *(gpio_map+offset) & bit;
  if (value)
    clear_event_detect(gpio);
  besRETURN_LONG(value);
besEND


besFUNCTION(sb_set_rising_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = RISING_ED_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= 1 << shift;
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_falling_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = FALLING_ED_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable) {
    *(gpio_map+offset) |= (1 << shift);
    *(gpio_map+offset) = (1 << shift);
  } else {
    *(gpio_map+offset) &= ~(1 << shift);
  }
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_high_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = HIGH_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= (1 << shift);
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_low_event)
  int gpio, enable;
  besARGUMENTS("ii")
    &gpio, &enable
  besARGEND
  int offset = LOW_DETECT_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (enable)
    *(gpio_map+offset) |= 1 << shift;
  else
    *(gpio_map+offset) &= ~(1 << shift);
  clear_event_detect(gpio);
besEND


besFUNCTION(sb_set_pullupdn)
  int gpio, pud;
  besARGUMENTS("ii")
    &gpio, &pud
  besARGEND
  int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
  int shift = (gpio%32);
  if (pud == PUD_DOWN)
    *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
  else if (pud == PUD_UP)
    *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
  else  // pud == PUD_OFF
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    short_wait();
    *(gpio_map+clk_offset) = 1 << shift;
    short_wait();
    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
    *(gpio_map+clk_offset) = 0;
besEND


besFUNCTION(sb_setup_gpio)
int gpio, direction, pud;
  besARGUMENTS("iii")
    &gpio, &direction, &pud
  besARGEND
  int offset = FSEL_OFFSET + (gpio/10);
  int shift = (gpio%10)*3;
  set_pullupdn(gpio, pud);
  if (direction == OUTPUT)
    *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
  else  // direction == INPUT
    *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
besEND


besFUNCTION(sb_gpio_function)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
    int offset = FSEL_OFFSET + (gpio/10);
    int shift = (gpio%10)*3;
    int value = *(gpio_map+offset);
    value >>= shift;
    value &= 7;
    besRETURN_LONG(value); // 0=input, 1=output, 4=alt0
besEND


besFUNCTION(sb_output_gpio)
  int gpio, value;
  besARGUMENTS("ii")
    &gpio, &value
  besARGEND
  int offset, shift;
  if (value) // value == HIGH
    offset = SET_OFFSET + (gpio/32);
  else       // value == LOW
    offset = CLR_OFFSET + (gpio/32);
  shift = (gpio%32);
  *(gpio_map+offset) = 1 << shift;
besEND


besFUNCTION(sb_input_gpio)
  int gpio;
  besARGUMENTS("i")
    &gpio
  besARGEND
  int offset, value, mask;
  offset = PINLEVEL_OFFSET + (gpio/32);
  mask = (1 << gpio%32);
  value = *(gpio_map+offset) & mask;
  besRETURN_LONG(value);
besEND


besFUNCTION(sb_cleanup)
  munmap((void *)gpio_map, BLOCK_SIZE);
besEND

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 24, 2019 5:22 am

@Heater,

I gave your fibo scheme code a try in the ScriptBasic TinyScheme extension module. I also ran the same fibo(70) using GMP.

Code: Select all

IMPORT ts.inc

sc = TS_New()
TS_Cmd sc, "(load \"init.scm\")"
ts_src = """
(define fibo (lambda (n)
    (let ((alpha (/  (+ 1 (sqrt 5)) 2) )
           (beta (/  (- 1 (sqrt 5)) 2) ))

      (round (- (* (/ 1 (sqrt 5)) (expt alpha n))
                (* (/ 1 (sqrt 5)) (expt beta n)))))))

(display (fibo 70))
(newline)
"""
PRINT FORMAT("%.0f",TS_Cmd(sc, ts_src)),"\n"
TS_Close sc
Output

Code: Select all

[email protected]:~/sb/examples/test$ time scriba fibo.sb
190392490709135

real	0m0.005s
user	0m0.001s
sys	0m0.005s
[email protected]:~/sb/examples/test$ time scriba fibo_scheme.sb
190392490700000

real	0m0.017s
user	0m0.007s
sys	0m0.010s
[email protected]:~/sb/examples/test$ 

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 24, 2019 7:02 am

I came up with a faster fibo in native ScriptBasic.

Code: Select all

f0 = 0
f1 = 1

FOR i = 1 TO 69
	f2 = f1 + f0
	f0 = f1
	f1 = f2
NEXT

PRINT FORMAT("%.0f",f2),"\n"

Code: Select all

$ time scriba fibo.bas
190392490709135

real	0m0.006s
user	0m0.000s
sys	0m0.007s
$

Here the time for the GMP base version.

Code: Select all

$ time scriba fibo.sb
190392490709135

real	0m0.005s
user	0m0.005s
sys	0m0.000s
$
Same times for fibo(78).

Code: Select all

[email protected]:~/sb/examples/test$ time scriba fibo.bas
8944394323791464

real	0m0.006s
user	0m0.001s
sys	0m0.006s
[email protected]:~/sb/examples/test$ time scriba fibo.sb
8944394323791464

real	0m0.005s
user	0m0.000s
sys	0m0.005s
[email protected]:~/sb/examples/test$ 

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Fri May 24, 2019 7:42 am

Why is that fibo_scheme.sb fibo(70) so terribly incorrect?

I get

Code: Select all

$ chibi-scheme fibo.chibi
190392490709135.0

User avatar
ScriptBasic
Posts: 945
Joined: Wed Apr 03, 2019 5:53 pm
Location: Anacortes, WA USA
Contact: Website Twitter

Re: ScriptBasic

Fri May 24, 2019 7:56 am

The best thing to do is test your Scheme code in another Scheme interpreter. The TinyScheme I compiled with is pretty old.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Fri May 24, 2019 8:00 am

But my Scheme fibo gives the correct answer as checked against any other fibo program.

Your fibo_scheme.sb does not.

Heater
Posts: 12141
Joined: Tue Jul 17, 2012 3:02 pm

Re: ScriptBasic

Fri May 24, 2019 8:13 am

@jahboater,
I think Heater means like in C where you pass the address of a function around, or perhaps have an array of functions which you can index.
No. When I said "functions are data." I had a lot more in mind. See below:

@ScriptBasic,
Something like this?
Certainly one can pass functions around in many languages. Typically indirectly via pointers or some such as in your ScriptBasic example or C.

I think there is a huge conceptual difference between that and having "functions as data". The thing about data is that it is the stuff my program deals with. It can read it, write it, change it, create it, delete it, copy it.

Having pointers or references to functions is nothing like the same. The pointers are data, the functions they point to are not.

Languages like Lisp, Scheme, Javascript, etc take this to a whole different level. Functions are data, the program can mess with them. The program is functions, the program can mess with itself!!

For example: How about writing a function, which creates an entirely new function composed from two supplied functions and returns it? That is functions as data in, and a new function as data out:

Code: Select all

; A simple function that  returns x * x
(define square (lambda (x)
  (* x x)
))

; A simple function that returns 1 / x
(define reciprocal (lambda (x)
  (/ 1 x )
))

; A "meta function" that makes a new function which is the function of a function...
; Parameters: f and g, functions of a single parameter x
; Return:     A function that in turn calculates f(g(x)) 
(define makeFuncOfFunc (lambda (f g)
    (lambda (x)
      (f (g x))
    ))
)

; Returns a function that calculates 1 / (x * x)
(define inverseSquare
  (makeFuncOfFunc reciprocal square)
)

; Returns a function that calculates the reciprocal of fibo(x) squared
(define inverseSquareFibo
  (makeFuncOfFunc inverseSquare fibo)
)

(display (inverseSquareFibo 42))
(newline)

Code: Select all

$ chibi-scheme junk.chibi
1.3931831825286213e-17
$
Of course all this awesome power of first class functions can lead to code that us mortals have trouble understanding...Throw in some closures and recursion and there is no chance.

But as the famous Mel said “If a program can't rewrite its own code, what good is it?”

The Story Of Mel: http://www.catb.org/~esr/jargon/html/story-of-mel.html

jahboater
Posts: 4185
Joined: Wed Feb 04, 2015 6:38 pm

Re: ScriptBasic

Fri May 24, 2019 8:30 am

Understood, and I agree.

Purely for amusement there was a thread here long ago about doing that in C.
You can mmap() a chunk of memory giving it execute permission (PROT_EXEC), copy in a function, and then execute it .......
Nasty live code.

User avatar
RichardRussell
Posts: 415
Joined: Thu Jun 21, 2012 10:48 am

Re: ScriptBasic

Fri May 24, 2019 9:03 am

Heater wrote:
Fri May 24, 2019 8:13 am
Of course all this awesome power of first class functions can lead to code that us mortals have trouble understanding...Throw in some closures and recursion and there is no chance.
I had some fun, many years ago, writing a BBC BASIC program that would implement the Rosetta Code First-class functions task. As it states in the comment, strictly speaking you cannot return a function in BBC BASIC (although you could return the code of a function in a string) so I return a function pointer instead, which you may consider to be cheating.

But it does demonstrate what can be achieved when the language provides low-level memory access (by means of indirection in the case of BBC BASIC) and can dynamically create new functions at run-time that way. My OOP library for BBC BASIC for Windows (CLASSLIB.BBC) is entirely reliant on that capability.

Return to “Other programming languages”