From 4e5de85c8429c295d8e8164413a54e22f394412a Mon Sep 17 00:00:00 2001 From: Robert van Engelen Date: Mon, 7 Sep 2020 09:13:47 -0400 Subject: [PATCH] Husky 2.6.1 --- README.md | 147 ++++++++++++++++++++++++++---------------------------- husky.pl | 19 +++---- 2 files changed, 82 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 34dbc63..2bdfaac 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ Lazy functional programming with Husky - [Types](#types) - [Examples](#examples) - [Functions](#functions) +- [Lambdas](#lambdas) - [List comprehension](#list-comprehension) - [Macros](#macros) - [Special constructs](#special-constructs) -- [Lambdas](#lambdas) - [Commands](#commands) - [Gotchas](#gotchas) - [Installation](#installation) @@ -212,7 +212,7 @@ Husky has three built-in type constructors: (alpha, beta) a tuple is the product of types alpha and beta alpha -> beta a function mapping elements of type alpha to type beta -New parametric data types and their constructors can be defined as follows: +New (parametric) data types and their constructors can be defined as follows: MyType :: type. Constructor1(arg1, arg2, ...) :: MyType(parm1, parm2, ...). @@ -258,65 +258,60 @@ Examples -------- > a := 2. - DEFINED a::num + { DEFINED a::num } > f(x) := x+1. - DEFINED f::num->num + { DEFINED f::num->num } > f(a). 3 :: num - % the same function f, now using the colon syntax: + % the same function f, using the colon syntax for application: > f:x := (+):x:1. - DEFINED f::num->num + { DEFINED f::num->num } - % the same function f, now using currying: + % the same function f, using currying: > f := +(1). - DEFINED f::num->num + { DEFINED f::num->num } - % In fact, the function definitions are translated into lambda expressions. For - % example, typing the function name returns its lambda expression: + % function definitions are translated to lambdas, + % typing the function name returns its lambda expression: > f(a) := a+1. - DEFINED f::num->num + { DEFINED f::num->num } > f. $0->$0+1 :: num->num > plus(x,y) := x+y. - DEFINED plus::num->num->num + { DEFINED plus::num->num->num } > plus. $0->$1->$0+$1 :: num->num->num - % A lambda expression can have alternative definitions (of the same type) - % separated by ';', for example the factorial function: - - % a function with argument specializations: + % a lambda can be specialized by multiple abstractions, each + % separated by a ';', e.g. the factorial function: > fact(0) := 1; fact(n) := n*fact(n-1). - DEFINED fac::num->num + { DEFINED fac::num->num } > fact. 0->1;$0->$0*fac($0-1) :: num->num > fact(6). 720 :: num - % Constants can be used to construct new data types, like BinTree: + % constants can be defined to construct new data types - % a BinTree type: + % declare a BinTree type: > BinTree :: type. - DECLARED BinTree::type. - - % define a type synonym (shortcut macro) for BinTree of num: - > Numtree == BinTree(num). + { DECLARED BinTree::type } - % define the Leaf constant: - > Leaf :: Numtree. - DECLARED Leaf::BinTree(num). + % define a Leaf constant: + > Leaf :: BinTree(*). + { DECLARED Leaf::BinTree($0) } - % define the Node constructor: - > Node(num, Numtree, Numtree) :: Numtree. + % define a Node constructor: + > Node(*, BinTree(*), BinTree(*)) :: BinTree(*). Node(num, BinTree(num), BinTree(num)) :: BinTree(num). - % Let's try it out by building a tree: + % try it out by building a small tree (see examples/btree.sky): > Node(3, Node(1, Leaf, Leaf), Node(4, Leaf, Leaf)). Node(3, Node(1, Leaf, Leaf), Node(4, Leaf, Leaf)) :: BinTree(num) @@ -421,6 +416,50 @@ Built-in operators and functions are defined in prelude.sky: curry curry function curry(f, x, y) := f((x, y)) uncurry uncurry function uncurry(f, (x, y)) := f(x, y) +Lambdas +------- + +A lamba (abstraction) is written as `v->b`. When a lambda has alternatives as +arguments for function specialization with choices among a collection of +argument values, such as constants and partial data structures, then the lambda +alternatives should be separated by semicolons (`;`): + + (v->b) a lambda abstraction + (v->b; w->c) a lambda with two specializations + +Argument `v` and `w` may be a name, a constant, or a constructor with named +parameters. The body of a lambda is just an expression. + +Lambdas in expression are parenthesized, because the `->` operator has a low +precedence. + +Function application is performed with the conventional syntax of argument +parameterization: + + > f := (x->x+1). + { DEFINED f::num->num } + > f(3). + 4 :: num + +However, applying a lambda directly to an argument requires the `:` application +operator: + + > (x->x+1):3. + 4 :: num + +Functions and functions with specializations are automatically translated to +the corresponding lambda abstractions when stored with the program: + + > f(x) := x+1. + { DEFINED f::num->num } + > f. + ($0->$0+1) :: (num->num) + > iszero(0) := true; + |: iszero(n) := false. + { DEFINED iszero::num->bool } + > iszero. + (0->true;$0->false) :: (num->bool) + List comprehension ------------------ @@ -515,50 +554,6 @@ For example: case n of (1 -> "one"; 2 -> "two"; 3 -> "three") -Lambdas -------- - -A lamba (abstraction) is written as `v->b`. When a lambda has alternatives as -arguments for function specialization with choices among a collection of -argument values, such as constants and partial data structures, then the lambda -alternatives should be separated by semicolons (`;`): - - (v->b) a lambda abstraction - (v->b; w->c) a lambda with two specializations - -Argument `v` and `w` may be a name, a constant, or a constructor with named -parameters. The body of a lambda is just an expression. - -Lambdas in expression are parenthesized, because the `->` operator has a low -precedence. - -Function application is performed with the conventional syntax of argument -parameterization: - - > f := (x->x+1). - { DEFINED f::num->num } - > f(3). - 4 :: num - -However, applying a lambda directly to an argument requires the `:` application -operator: - - > (x->x+1):3. - 4 :: num - -Functions and functions with specializations are automatically translated to -the corresponding lambda abstractions when stored with the program: - - f(x) := x+1. - { DEFINED f::num->num } - f. - ($0->$0+1) :: (num->num) - > iszero(0) := true; - |: iszero(n) := false. - { DEFINED iszero::num->bool } - > iszero. - (0->true;$0->false) :: (num->bool) - Commands -------- @@ -660,7 +655,7 @@ After starting Husky, load any one of the example .sky files with: > load "examples/". -To delete examples from memory and reset Husky to system defaults: +To delete programs from memory and reset Husky to system defaults: > reset. @@ -673,7 +668,9 @@ commands: > save. > bye. -This creates the `Husky' executable with the prelude functions preloaded. +This creates the `Husky' executable with the prelude functions preloaded. You +can also load one or more programs and then save the executable with the +programs included. Husky source files: diff --git a/husky.pl b/husky.pl index 90be615..7fb988d 100644 --- a/husky.pl +++ b/husky.pl @@ -27,6 +27,7 @@ % 2.4 4/19/2009 added list comprehensions as macros in prelude.sky % 2.5 11/22/2009 compatible with SWI Prolog 5.10.4 % 2.6 8/31/2020 compatible with SWI Prolog 8.2.1 +% 2.7 9/4/2020 work around SWI Prolog 8.2.1 bug % % License: GNU Public License (GPL) % Author (c) 1999-2020: Robert A. van Engelen @@ -41,19 +42,17 @@ library(statistics) ]). -% Set SWI-Prolog flags -:- set_prolog_flag(allow_dot_in_atom, true), +% Set SWI-Prolog flags and operator precedences and associativities + +init :- + set_prolog_flag(allow_dot_in_atom, true), set_prolog_flag(back_quotes, symbol_char), set_prolog_flag(character_escapes, false), set_prolog_flag(allow_variable_name_as_functor, true), set_prolog_flag(optimise, true), set_prolog_flag(print_write_options, [module(husky), quoted(true)]), - set_prolog_flag(history, 100). - -% Set operator precedences and associativities - -set_ops :- + set_prolog_flag(history, 100), op(1098, fx, husky:[prefix, postfix, infix, infixl, infixr]), op(1098, xfx, husky:[prefix, postfix, infix, infixl, infixr]), op(974, xfx, husky:[==]), @@ -70,7 +69,7 @@ op(100, xfy, husky:['.']), op(100, fx, husky:[remove, load, save]). -:- set_ops. +:- init. % husky/0 % Start a new Husky REPL and perform a soft reset @@ -84,6 +83,8 @@ % Read-evaluate-print loop repl :- + init, + module(husky), % an ugly hack to work around read_history(... [module(husky)]) bug repeat, read_history(history, '!history', [module(husky), end_of_file], '~!> ', Term, Bindings), husky(Term, Bindings), Term == bye, !. @@ -154,7 +155,7 @@ erase(Ref), fail. pragma(reset) :- !, - set_ops, + init, husky(load "prelude"). pragma(save) :- qsave_program('Husky', [goal = true, toplevel = repl, op = save]), !.