Multi Paradigm Weenie

Favourite languages: ObjectiveCaml, OzLanguage, MyFavoriteLanguage. Some will even admit to liking CeePlusPlus. CommonLisp has its fair share, though not as much as the traditional SmugLispWeenie

Favourite paradigms: all of them. The inability of a language to adequately support any one of ImperativeProgramming, ObjectOrientedProgramming, FunctionalProgramming, LogicProgramming, DataflowProgramming, ConstraintProgramming, CollectionOrientedProgramming, ConcurrentProgramming or the RelationalModel, is greeted with scowls and muttering.

Favourite books: ConceptsTechniquesAndModelsOfComputerProgramming, AdvancedProgrammingLanguageDesign

CollectionOrientedProgramming? Is that a "recognized" paradigm? I can hazard a guess as to what it is, but it smells to me like TableOrientedProgramming--a DesignPattern that someone is itching to promote to full-fledged paradigm. :)

Yes, it is -- discussion moved to CollectionOrientedProgramming.

MultiParadigmWeenies believe that the ObjectRelationalImpedanceMismatchDoesNotExist. (That page is a mess, so: they think that the libraries and/or language should make it go away.)

Has a StaticTyping subculture who are able to either do bizarre and incomprehensible things with TemplateMetaprogramming, or understand DependentTypes and CategoryTheory -- but rarely both.


Who wants to take a stab at writing a HelloWorld program that uses all of the above ProgrammingParadigms? Feel free to use any language you deem appropriate, including making up your own or using multi-paradigm pseudocode.

You mean use all of them at the same time? That's a bit much; that only has two parts, print, and a string; there are more paradigms than there are tasks to accomplish. How about 8 queens?


I was bored last night. :) Here's a multi-paradigm HelloWorld. It's written in a MyFavoriteLanguage called Alohomora, which is my spare-time VaporWare and hence doesn't exist yet. More specifically, it's written in a LiterateProgramming system called Quill, which also doesn't exist. But the problem description did say it could even be in pseudocode, so I think this is a step up.

[File: hello_world.quill]

This program creates an exceptionally roundabout solution to the classic "Hello World" problem: write the string "Hello world!" on the screen. We first generate a collection of Flyweight character objects, stored in a container that manages requests for them. We then use a non-deterministic choice algorithm to select only those characters that will appear in the final string. The 'l' and 'o' characters are duplicated, the originals serving as prototypes. The characters are then mapped into a relational table through a mathematical algorithm that assigns a sequence number to them, using monadic continuation passing style. A relational query orders the objects and projects them down to the character only. Then we do a map:as: to convert the result set into a string, and print the result. We use an aspect to advice print to print a ! after everything.

First we need our character objects. These are simple wrappers, needing no other fields. There really is no body to this: a default constructor's generated that copies a <char> and then calls (morph c into: <char-wrapper>) to change the copy's type. The <flyweight> metaclass wraps that to memoize requests, so it doesn't create new objects each time.

  defclass <char-wrapper> extends: <char> metaclass: <flyweight>

We also want a container for them. Instead of wrapping a collection class, we can lazily generate objects as requests come in, knowing that the <flyweight> metaclass will memoize the actual objects. We do need to supply a method on <iterator>, though. This one creates an iterator for the range ASCII_MIN..ASCII_MAX, creates a function that converts an ASCII code into a <char>, and then rebinds the get method on the iterator to the constructor for a <char-wrapper>

  defconst ASCII-MIN 33
  defconst ASCII-MAX 127
  defclass <char-generator> extends: <collection>
  def <iterator> [collection :: <char-generator>]
    base <- <iterator> ASCII-MIN..ASCII-MAX
    ascii2char <- bind as <char> base.get
    set base.get to: compose <char-wrapper> ascii2char
    base

The next step is to select only those objects that will be in the final string. The simple solution is simply 'filter <char-generator>() with: (it in "Helowrd!")'. However, if we wanted this to be simple, we would simply have done 'print "Hello world!", and that would've been no fun. So we use the non-deterministic 'amb' operator (taken from StructureAndInterpretationOfComputerPrograms, which stole it from some Lisp dialect), and choose from alternatives with 'require'. Amb is a little different in Alohomora than in Scheme: instead of taking a list of arguments, it takes a single iterator, and then non-deterministically tries each.

  def filter-characters [generator :: <char-generator>]
    possibilities <- amb (<iterator> generator)
    require (it in "owl herd")
    all-values possibilities

filter-characters has now returned a <sequence> (more specifically, a <cons-list>). So now let's tail-call our way down the list and make copies of the duplicated letters.

  def maybe-copy-letter [list :: <cons-list>, accumulator :: <cons-list>]
    maybe-copy-letter list.tail (...
    case list.head
      "l": accumulator & repeat list.head 3
      "o": accumulator & repeat list.head 2
      else: accumulator
    )

def copy-letters [selected-chars :: <cons-list>] maybe-copy-letter selected-chars nil

Now comes the tricky part. We need to assign sequence numbers to each letter. And we don't know what order they'll be in, as a consequence of the non-deterministic assignment (actually, non-determinism usually means depth-first, but at this stage I'm not going to guarantee that). We do know that repeated letters will all be in a row. The simplest thing to do here would be a lookup table, which is exactly why I'm not going to do that. Instead, lets QuickSort it!

  def quicksort-chars [letter-set :: <cons-list>]
    pivot <- letter-set.head
    quicksort-chars [x | x < pivot] & pivot & quicksort-chars [x | x > pivot]

Now we can define a mapping function that associates a sequence number with each character and returns the resulting tuple.

  l-seen <- 0
  o-seen <- 0
  def char-order [c :: <char-wrapper>]
    case c
      "H": 1
      "e": 2
      "l": ++l-seen
           case l-seen
             1: 3
             2: 4
             3: 10
      "o": ++o-seen
           case o-seen
             1: 5
             2: 8
      " ": 6
      "w": 7
      "r": 9
      "d": 11

(Yes, the sorting was completely gratuitous. I stuck it in because ListComprehensions are monads, and so I can claim MonadicProgramming without actually knowing what it is or how to create one.)

We're almost there. The next step is to create a function to turn a character into <character, sort-order> tuple.

  def make-tuple [c :: <char-wrapper>]
    [char: ?c, sort-order: ?(char-order c)]

To create the relation, we just map the tuple-generator over the list of characters.

  def make-relation [sorted-list :: <sequence>]
    relvar <- <relation>
    map (make-tuple it) over: sorted-list into: relvar
    relvar

Then we collapse the relation down into a single list:

  def collapse-relation [relation :: <relation>]
    sorter <- bind order relation by: 'sort-order
    projection <- bind project 'char
    (compose values <dictionary> projection sorter)()

This returns a <sequence> of the values of the char column, ordered by sort-order. A <string> is just a sequence of <char>s. Since <char-wrapper> is a subtype of <char>, we've effectively got the string "Hello world". We need to add the ! on as an aspect

  defaspect exclamatize
    printers <- pointcut [print output]
    around printers
      call-next-method output & "!"

The only thing left is to put everything together.

  program <- compose print collapse-relation make-relation quicksort-chars ...
                     copy-letters filter-characters <char-generator>
  program()

And this concludes the program. [end]

Yeah. I believe that's ImperativeProgramming, FunctionalProgramming, LiterateProgramming, ObjectOrientedProgramming, TableOrientedProgramming, MonadicProgramming, GenericProgramming, NonDeterministicProgramming?, GenericFunctions, MetaClasses, and HigherOrderFunctions. There're shades of PrototypeBasedProgramming in the letter-copying too. And you might be able to consider that massive composition of functions that passes for the main program to be FlowBasedProgramming, or maybe DataflowProgramming. Am I a MultiParadigmWeenie yet? -- JonathanTang

WeenieDom? is hereby granted. [Taps Jonathan on the shoulder with a cordless power screwdriver.] You now go forth and whine about how your demonstrably superior technology is being oppressed by the entrenched commercial interests who are conspiring to keep programmers 'round the world peddled to their obsolete, archaic junk. The registrar of our elite society, PaulGraham, will now add your name to the roster. Congratulations! -- LordProtectorOfAllWeenies?

[I'm with the LordProtector?; you're in!!!! -- dm]


An extreme MultiParadigmWeenie is someone who uses multiple paradigms because they simply get bored using a few. MentalMasturbation. This does not imply that all MultiParadigmWeenies are like this. It is only an extreme form.

You almost sound like you think that's a bad thing. No MultiParadigmWeenieDom? for you. MentalMasturbationIsHealthyExercise?.

Only if your employer wants to foot the bill for your learning and experiments and wants to risk limiting the candidates of your replacement if you leave.


See also: MixingParadigms, ProgrammingParadigm, MultiParadigmProgrammingLanguage, WhenToUseWhatParadigm


CategoryWeenie


EditText of this page (last edited September 14, 2012) or FindPage with title or text search