#1  
Old 09-25-2020, 11:53 PM
ceptimus's Avatar
ceptimus ceptimus is offline
puzzler
 
Join Date: Aug 2004
Location: UK
Posts: XVMMDCCXC
Images: 28
Default Clojure

I'm taking a break from the Dart programming language and playing with the Clojure language. Clojure is a modern Lisp, and Lisp is one of the oldest computer languages around - invented in 1958 - only Fortran is older.

I've no idea what I'm doing really - just blundering around till the thing compiles and runs. I've written a sudoku solver as a learning exercise. Here's part of it.

Code:
(defn rmk [p] ; puzzle
  (loop [q p r (knowns p)]
    (if (empty? r)
      (if (< (count (knowns p)) (count (knowns q)) 81)
        (rmk q) ;found some new knowns (but not yet found all 81) so run again
        q) ;return puzzle 
      (recur (rma q (links (first (keys r))) (first (vals r))) (rest r)))))
Clojure is pretty mind-bending because everything's immutable - there's no easy way to even have a loop variable that increments without using recursion. :chin:

Also, lots of parentheses.



I don't think I'll use Clojure seriously, but I may pick up a few concepts that will be useful when writing programs in other languages.
__________________
Reply With Quote
Thanks, from:
Crumb (09-26-2020), Ensign Steve (09-26-2020), fragment (09-26-2020), JoeP (09-26-2020), Kyuss Apollo (09-26-2020), lisarea (09-26-2020), slimshady2357 (09-26-2020), SR71 (09-26-2020), Stormlight (09-28-2020)
  #2  
Old 09-26-2020, 09:50 AM
fragment's Avatar
fragment fragment is offline
mesospheric bore
 
Join Date: Jul 2005
Location: New Zealand
Gender: Male
Posts: VMCDXLIV
Blog Entries: 8
Images: 143
Default Re: Clojure

I haven't tried Clojure, but I am functional programming curious and have been trying to write R in a more functional style.

Isn't the idea to avoid loop constructs if possible? The usual reason for an incrementing loop variable is to use as an index to refer to elements of some array/vector/whatever but in a functional language you can use map, filter or reduce instead.
Reply With Quote
Thanks, from:
ceptimus (09-26-2020), Stormlight (09-28-2020)
  #3  
Old 09-26-2020, 12:49 PM
ceptimus's Avatar
ceptimus ceptimus is offline
puzzler
 
Join Date: Aug 2004
Location: UK
Posts: XVMMDCCXC
Images: 28
Default Re: Clojure

Quote:
Originally Posted by fragment View Post
Isn't the idea to avoid loop constructs if possible? The usual reason for an incrementing loop variable is to use as an index to refer to elements of some array/vector/whatever but in a functional language you can use map, filter or reduce instead.
Absolutely right. But after many years of procedural programming, I tend to reach for loop constructs to tackle pretty much everything, and it's frustrating when they're not available.

For example, my sudoku program has deeply nested recursive routines to solve a puzzle. The top level routine loads puzzles to solve from a .sdm file which is a standard sudoku community ASCII file that contains one puzzle on each line of the file. The one I'm using to test my program has over a thousand puzzles.

So I think, "I'll use a loop that loads one puzzle at a time, then pass that puzzle to the solver, and once the solver has finished, move on to the next puzzle." I also want to print each puzzle to the screen, along with its line-number in the .sdm file. How to do that without an incrementing loop variable? It's possible, of course - and once you begin to think in the Clojure way it begins to look elegant.

Clojure has the idea of 'lazy sequences' that produce lists of things, but each item in the list is only generated when it's needed. You can have things that all look the same, but have different types. For example here I define a, b, and c all of which look the same when printed in the REPL (interactive Clojure console) but have different types.

Code:
=> (def a (range 0 10))
a
=> a
(0 1 2 3 4 5 6 7 8 9)
=> (type a)
clojure.lang.LongRange
=> (def b (take 10 (range)))
b
=> b
(0 1 2 3 4 5 6 7 8 9)
=> (type b)
clojure.lang.LazySeq
=> (def c (into () (range 9 -1 -1)))
c
=> c
(0 1 2 3 4 5 6 7 8 9)
=> (type c)
clojure.lang.PersistentList
You can pass those three different types (and plenty of others) to the same map operation, and the output is identical. Here I'm mapping an anonymous function that multiplies by two to each of a, b, c

Code:
=> (map #(* % 2) a)
(0 2 4 6 8 10 12 14 16 18)
=> (map #(* % 2) b)
(0 2 4 6 8 10 12 14 16 18)
=> (map #(* % 2) c)
(0 2 4 6 8 10 12 14 16 18)
In each case the type of the output is a clojure.lang.LazySeq because map is prepared to accept pretty much any kind of collection but always returns a lazy sequence. I think map kind-of uses seq internally because seq returns a sequence on any collection. :chin:

But even the operation of seq confuses me. (seq a), (seq b), and (seq c) all produce output that looks just like a, b, c alone. (seq a) has the same type as a, and (seq c) has the same type as c, but (seq b) has type clojure.lang.Cons :wtf:

I get very confused, but I suppose that's an important stage of any learning process.
__________________

Last edited by ceptimus; 09-26-2020 at 01:21 PM. Reason: swapped to using => to show my input to the REPL, rather than its output
Reply With Quote
Thanks, from:
fragment (09-27-2020), JoeP (09-26-2020), Stormlight (09-28-2020)
  #4  
Old 09-26-2020, 05:33 PM
JoeP's Avatar
JoeP JoeP is online now
Solipsist
 
Join Date: Jul 2004
Location: Kolmannessa kerroksessa
Gender: Male
Posts: XXXVMMXII
Images: 18
Default Re: Clojure

Quote:
Originally Posted by ceptimus View Post
Also, lots of parentheses.
)))))))))))))))))))))))))))))))))))))))))))))))))) - Freethought Forum
__________________

:roadrun:
Free thought! Please take one!

:unitedkingdom:   :southafrica:   :unitedkingdom::finland:   :finland:
Reply With Quote
Thanks, from:
ceptimus (09-26-2020), Ensign Steve (09-26-2020), fragment (09-27-2020), mickthinks (10-27-2020), Stormlight (09-28-2020)
  #5  
Old 09-27-2020, 09:48 AM
fragment's Avatar
fragment fragment is offline
mesospheric bore
 
Join Date: Jul 2005
Location: New Zealand
Gender: Male
Posts: VMCDXLIV
Blog Entries: 8
Images: 143
Default Re: Clojure

Quote:
Originally Posted by ceptimus View Post
So I think, "I'll use a loop that loads one puzzle at a time, then pass that puzzle to the solver, and once the solver has finished, move on to the next puzzle." I also want to print each puzzle to the screen, along with its line-number in the .sdm file. How to do that without an incrementing loop variable? It's possible, of course - and once you begin to think in the Clojure way it begins to look elegant.
Yeah, I don't really have the hang of it. R apparently performs best in a functional style but also allows all the procedural stuff. So I end up with an ugly kludge instead. Which is OK for quick data tinkering and analyses but I'd like to produce cleaner code.
Reply With Quote
Thanks, from:
ceptimus (09-27-2020), Stormlight (09-28-2020)
  #6  
Old 09-27-2020, 10:16 AM
fragment's Avatar
fragment fragment is offline
mesospheric bore
 
Join Date: Jul 2005
Location: New Zealand
Gender: Male
Posts: VMCDXLIV
Blog Entries: 8
Images: 143
Default Re: Clojure

Speaking of kludge, I have a couple of times resorted to passing an integer sequence to `*apply` (R's family of map-equivalents) and using that as an index for referring to the lists/vectors of interest within the passed function. Which works because of the way R handles scope, but functional style it ain't.
Reply With Quote
Thanks, from:
ceptimus (09-27-2020), Stormlight (09-28-2020)
  #7  
Old 10-26-2020, 05:48 AM
fragment's Avatar
fragment fragment is offline
mesospheric bore
 
Join Date: Jul 2005
Location: New Zealand
Gender: Male
Posts: VMCDXLIV
Blog Entries: 8
Images: 143
Default Re: Clojure

Can we make this a generic FP thread? I've been playing with Elm and it's really cool.

It's a language for web front-ends. It compiles to... Javascript! Because it is strongly typed and has no side effects (within the language, the runtime handles IO based on program state and messages) there are no runtime errors and no weird unhandled states.

So far I'm only just getting my head around the language and app architecture, but definitely seeing the potential in spending my time making high level descriptions of my interface and data rather than getting lost in the JS weeds.
Reply With Quote
Thanks, from:
ceptimus (10-26-2020), Crumb (10-26-2020), Ensign Steve (10-27-2020), specious_reasons (10-26-2020)
  #8  
Old 12-23-2020, 07:39 AM
fragment's Avatar
fragment fragment is offline
mesospheric bore
 
Join Date: Jul 2005
Location: New Zealand
Gender: Male
Posts: VMCDXLIV
Blog Entries: 8
Images: 143
Default Re: Clojure

Right so everyone with even a passing interest in making front-ends for web apps should give Elm a try. Great as My First Functional Programming Language - making stuff in it teaches concepts without needing to understand heavy theory first. The intro ( Introduction ยท An Introduction to Elm ) is clear and bite-sized, the friendly compiler tells you where you've gone wrong and how to fix it, there are online sandboxes so you don't need to install to try it out ( buttons ), and Youtube vids of various talks give you a sense of what's possible and how to go about it.

Seriously, try it out.
Reply With Quote
Thanks, from:
Ensign Steve (01-11-2021), JoeP (12-23-2020), mickthinks (12-23-2020), specious_reasons (12-23-2020)
Reply

  Freethought Forum > The Marketplace > Computers & Technology


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

 

All times are GMT +1. The time now is 07:54 AM.


Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Page generated in 0.66141 seconds with 13 queries