# comment on a line by itself. The next is a command by itself:
set var1 $value1
set var2 $value2 ; # comment that follows a line of code


quibble = ([most..., last]) ->
  '{' +
    (most.join ', ') +
    (if most.length then ' and ' else '')  +
    (last or '') +
  '}'

console.log quibble(s) for s in [ [], ["ABC"], ["ABC", "DEF"],
                                  ["ABC", "DEF", "G", "H" ]   ]


(defun quibble (&rest args)
  (format t "{~{~a~#[~; and ~:;, ~]~}}" args))

(quibble)
(quibble "ABC")
(quibble "ABC" "DEF")
(quibble "ABC" "DEF" "G" "H")


© This is a comment. Everything from © to the end of the line is ignored.


10 REM this is a comment
20

40 REM from above you can see that line numbers with no statement
50 REM and blank lines also are ignored


#! Everything on this line (after the shebang to the left) will be ignored.


//This is a one line comment. There are no other commenting options in TorqueScript.


include "cowgol.coh";

sub quibble(words: [[uint8]],
            length: intptr,
            buf: [uint8]):
           (out: [uint8]) is
    sub append(s: [uint8]) is
        while [s] != 0 loop
            [buf] := [s];
            buf := @next buf;
            s := @next s;
        end loop;
    end sub;

    out := buf;

    append("{");
    while length > 0 loop
        append([words]);
        words := @next words;
        case length is
            when 1: break;
            when 2: append(" and ");
            when else: append(", ");
        end case;
        length := length - 1;
    end loop;
    append("}");

    [buf] := 0;
end sub;

var w1: [uint8][] := {};
var w2: [uint8][] := {"ABC"};
var w3: [uint8][] := {"ABC","DEF"};
var w4: [uint8][] := {"ABC","DEF","G","H"};

print(quibble(&w1[0], @sizeof w1, LOMEM)); print_nl();
print(quibble(&w2[0], @sizeof w2, LOMEM)); print_nl();
print(quibble(&w3[0], @sizeof w3, LOMEM)); print_nl();
print(quibble(&w4[0], @sizeof w4, LOMEM)); print_nl();


import std.stdio, std.string;

string quibbler(in string[] seq) pure /*nothrow*/ {
    if (seq.length <= 1)
        return format("{%-(%s, %)}", seq);
    else
        return format("{%-(%s, %) and %s}", seq[0 .. $-1], seq[$-1]);
}

void main() {
    //foreach (immutable test; [[],
    foreach (const test; [[],
                          ["ABC"],
                          ["ABC", "DEF"],
                          ["ABC", "DEF", "G", "H"]])
        test.quibbler.writeln;
}


--## comments are prefixed with a long handed double paintbrush


// This is a line comment.
/* This is a single line block comment.*/
/* This is
   a multi-line
   block comment.*/


@# old-style comment to end of line
@; new-style comment to end of line
@(bind a ; comment within expression
       "foo")


#!/bin/sh
# A leading hash symbol begins a comment.
echo "Hello"      # Comments can appear after a statement.

# The hash symbol must be at the beginning of a word.
echo This_Is#Not_A_Comment
#Comment


$ list = "[]"
$ gosub comma_quibbling
$ write sys$output return_string
$
$ list = "[""ABC""]"
$ gosub comma_quibbling
$ write sys$output return_string
$
$ list = "[""ABC"", ""DEF""]"
$ gosub comma_quibbling
$ write sys$output return_string
$
$ list = "[""ABC"", ""DEF"", ""G"", ""H""]"
$ gosub comma_quibbling
$ write sys$output return_string
$
$ exit
$
$ comma_quibbling:
$ list = list - "[" - "]"
$ return_string = "{}"
$ if list .eqs. "" then $ return
$ return_string = "{" + f$element( 0, ",", list ) - """" - """"
$ if f$locate( ",", list ) .eq. f$length( list ) then $ goto done2
$ i = 1
$ loop:
$  word = f$element( i, ",", list ) - """" - """"
$  if word .eqs. "," then $ goto done1
$  return_string = return_string - "^" + "^," + word
$  i = i + 1
$  goto loop
$ done1:
$ return_string = f$element( 0, "^", return_string ) + " and" + ( f$element( 1, "^", return_string ) - "," )
$ done2:
$ return_string = return_string + "}"
$ return


comma-quibble lst:
	"}" )
	if lst:
		pop-from lst
		if lst:
			" and "
			pop-from lst
			for item in lst:
				item ", "
	concat( "{"

!. comma-quibble []
!. comma-quibble [ "ABC" ]
!. comma-quibble [ "ABC" "DEF" ]
!. comma-quibble [ "ABC" "DEF" "G" "H" ]


# this is a comment
# this is another comment


# this is single line a comment

# this is a\
continued comment

(# this is a
multi-line comment #)

(# comments in (# this form #) can (#
be (# arbitrarily #) #) nested #)

---- this is also a comment\
and can be continued

###
The whole rest of the file after three hashes
is a comment.


//////////////////////////////////////////////////////////////////////////////////////////////
//
// Line Comments:
// =============
//
@VAR v1 = 10; // Line comments start from the "//" and continue to end of the line.
//               (normal code can appear on the same line, before the //)
//
//   Line comments can span a complete line, or start in the middle of a line.
///
//// Additional // chars and /* /*  /[  ]/ and  /] are ignored
//// Line comments can be appear to be nested, since any additional // is ignored.
///
//   Note: // can appear in strings without triggering a line comment
//         // cannot appear inside an operator (or verbname), since a line comment
//            would start
//
/////////////////////////////////////////////////////////////////////////////////////////////

/********************************************************************************************
 *
 *  Block Comments:
 *  ==============
 *
 ********************************************************************************************/
//*
//*  These start with /* and end with the next */ .  They cannot be nested, since the first */
//*  will end the block comment.  For example, the comment, /* /* */ */ would end after the
//*  first */. Note that /* is ignored inside a block comment, as are   //   /[   /] and  /].
//*
//*  Also note that something like the following will cause trouble in a block comment:
//*
//*    /* comments                          //
//*     * more comments                     //   */  (the // does not prevent the */ from ending
//*     * (no longer part of the comment)   //        block comment)
//*     */
//*
//*    Note: /* can appear in strings without triggering the start of a block comment
//*          /* cannot appear inside an operator (or verbname), since a line comment will
//*             start, although */ is allowed inside an operator (verbname).  Commenting
//*             out such a verbname may cause problems.
//*
//*    Note: Since string literals are not recognized in block comments, */ appearing
//*          in a string literal inside a block comment (perhaps commented-out code)
//*          will cause the block comment to end.
//*
//*    Note: It is an error to start a block comment and not end it, so that it is still
//*          in progresss when the end-of-file is reached.
//*
//*    Block comments can appear inside lines of code:
//*
/*1*/@VAR/*2*/v2/*3*/=/*4*/20/*5*/;/*6*/  // a line comment can follow block comments on the
                                           // same line

/[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
/[]                                                                                []
/[]     Nestable Block Comments:                                                             []
 []     ========================                                                             []/
 []                                                                                []/
 [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]/

//[]
//[]  These start with /[ and end with the next matching ]/ .  Additional occurrences
//[]  of /[ ... ]/ can appear inside a nestable block comment.  The nestable block comment
//[]  will end only when the nest level reaches 0.  Note that /* is ignored inside a nestable
//[]  block comment, as are  */   //  and  /].
//[]
//[]  Nestable block comments can be used to comment out blocks of code containing line
//[]  comments or regular comments, and even balanced and well-formed nestable block comments.
//[]
//[]    Note: /[ can appear in strings without triggering the start of a block comment.
//[]          However, strings literals are not recognized inside a nestable block comment, so
//[]          any appearances of /[ and /] inside a string literal in a nestable block commment
//[]          will affect the nest level, and may cause problems.
//[]
//[]    Note: It is an error to start a nestable block comment and not end it, so that it is
//[]          still in progresss when the end of file is reached.
//[]
//[]    Nestable block comments can appear inside lines of code:
//[]
/[1]/@VAR/[2]/v3/[3]/=/[4]/30/[5]/;/[6]/  // a line comment can follow nestable block comments
                                          // on the same line

@SAY v1 v2 v3;                            // should see:   10 20 30

/]
/=================================================================================================\
|                                                                                |
|   /] starts a block comment that lasts until the end of the current file.  Everything after     |
|   the /] is ignored.                                                                            |
|                                                                                |
\=================================================================================================/


// Single line commment.

/*
   Multiple
   line
   comment.
*/


(lib 'match)

(define (quibble words)
    (match words
         [ null "{}"]
         [ (a)  (format "{ %a }" a)]
         [ (a b) (format "{ %a and %a }" a b)]
         [( a ... b c) (format "{ %a %a and %a }" (for/string ([w a]) (string-append w ", "))  b c)]
         [else 'bad-input]))

;; output

 (for ([t '(() ("ABC") ("ABC" "DEF") ("ABC" "DEF" "G" "H"))])
    (writeln t '----> (quibble t)))

null     ---->     "{}"
("ABC")     ---->     "{ ABC }"
("ABC" "DEF")     ---->     "{ ABC and DEF }"
("ABC" "DEF" "G" "H")     ---->     "{ ABC, DEF, G and H }"


let a = 4 " A valid comment
echo "foo" " Not a comment but an argument that misses the closing quote


'comment
Rem comment
#If 0
  Technically not a comment; the compiler may or may not ignore this, but the
  IDE won't. Note the somewhat odd formatting seen here; the IDE will likely
  just mark the entire line(s) as errors.
#End If


' This is a comment
REM This is also a comment
Dim comment as string ' You can also append comments to statements
Dim comment2 as string REM You can append comments to statements


// This is a comment
/* This is a comment */
* This is a comment
&& This is a comment
NOTE This is a commen
* This is a comment
&& This is a comment
NOTE This is a commen


// This is a single line comment.
/*
This is a multiline comment.
   /* It can be nested. */
*/


class
	APPLICATION

create
	make

feature

		make
			-- Test of the feature comma_quibbling.
		local
			l: LINKED_LIST [STRING]
		do
			create l.make
			io.put_string (comma_quibbling (l) + "%N")
			l.extend ("ABC")
			io.put_string (comma_quibbling (l) + "%N")
			l.extend ("DEF")
			io.put_string (comma_quibbling (l) + "%N")
			l.extend ("G")
			l.extend ("H")
			io.put_string (comma_quibbling (l) + "%N")
		end

	comma_quibbling (l: LINKED_LIST [STRING]): STRING
			-- Elements of 'l' seperated by a comma or an and where appropriate.
		require
			l_not_void: l /= Void
		do
			create Result.make_empty
			Result.extend ('{')
			if l.is_empty then
				Result.append ("}")
			elseif l.count = 1 then
				Result.append (l [1] + "}")
			else
				Result.append (l [1])
				across
					2 |..| (l.count - 1) as c
				loop
					Result.append (", " + l [c.item])
				end
				Result.append (" and " + l [l.count] + "}")
			end
		end

end


// This is a line comment.
/* This is a single line block comment.*/
/* This is
   a multi-line
   block comment.*/
/* This is/* a nested */block comment.*/


// This is a single line comment

/*
  This comment spans
  multiple lines
*/


// Comments are denoted by a preceding double slash or or single quote
' and continue to the end of the line. There are no multi-line comment blocks
Dim foo As Integer // Comments can also occupy the ends of code lines


Text(0, \comment\ "Hello \not a comment\ World!"); \comment


defmodule RC do
  def generate( list ), do: "{#{ generate_content(list) }}"

  defp generate_content( [] ), do: ""
  defp generate_content( [x] ), do: x
  defp generate_content( [x1, x2] ), do: "#{x1} and #{x2}"
  defp generate_content( xs ) do
    [last, second_to_last | t] = Enum.reverse( xs )
    with_commas = for x <- t, do: x <> ","
    Enum.join(Enum.reverse([last, "and", second_to_last | with_commas]), " ")
  end
end

Enum.each([[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]], fn list ->
  IO.inspect RC.generate(list)
end)


-module( comma_quibbling ).

-export( [task/0] ).

task() -> [generate(X) || X <- [[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]]].

generate( List ) -> "{" ++ generate_content(List) ++ "}".

generate_content( [] ) -> "";
generate_content( [X] ) -> X;
generate_content( [X1, X2] ) -> string:join( [X1, "and", X2], " " );
generate_content( Xs ) ->
	[Last, Second_to_last | T] = lists:reverse( Xs ),
	With_commas = [X ++ "," || X <- T],
	string:join(lists:reverse([Last, "and", Second_to_last | With_commas]), " ").


let quibble list =
    let rec inner = function
        | [] -> ""
        | [x] -> x
        | [x;y] -> sprintf "%s and %s" x y
        | h::t -> sprintf "%s, %s" h (inner t)
    sprintf "{%s}" (inner list)

// test interactively
quibble []
quibble ["ABC"]
quibble ["ABC"; "DEF"]
quibble ["ABC"; "DEF"; "G"]
quibble ["ABC"; "DEF"; "G"; "H"]


<!-- Comment syntax is borrowed from XML and HTML. -->


// This is a single line comment
/*
  This comment spans
  multiple lines
*/


// This is a normal comment in Zig
/// This is a documentation comment in Zig (for the following line)


x=1; // comment ala C++
x=2; # ala scripts
/* ala C, these comments are parsed (also ala C) */
/* can /* be */ nested */
#if 0
  also ala C (and parsed)
#endif
#<<<#
  "here" comment, unparsed
#<<<#


program comments        # this program does nothing

# zoea supports single line comments starting with a '#' char

/*
  zoea also supports
  multi line
  comments
*/


USING: inverse qw sequences ;

: (quibble) ( seq -- seq' )
    {
        { [ { } ] [ "" ] }
        { [ 1array ] [ ] }
        { [ 2array ] [ " and " glue ] }
        [ unclip swap (quibble) ", " glue ]
    } switch ;

: quibble ( seq -- str ) (quibble) "{%s}" sprintf ;

{ } qw{ ABC } qw{ ABC DEF } qw{ ABC DEF G H }
[ quibble print ] 4 napply


: read  bl parse ;
: not-empty? ( c-addr u -- c-addr u true | false ) ?dup-if true else drop false then ;
: third-to-last  2rot ;
: second-to-last  2swap ;

: quibble
	." {"
	read read begin read not-empty? while third-to-last type ." , " repeat
	second-to-last not-empty? if type then
	not-empty? if ."  and " type then
	." }" cr ;

quibble
quibble ABC
quibble ABC DEF
quibble ABC DEF G H


      SUBROUTINE QUIBBLE(TEXT,OXFORDIAN)	!Punctuates a list with commas and stuff.
       CHARACTER*(*) TEXT	!The text, delimited by spaces.
       LOGICAL OXFORDIAN	!Just so.
       INTEGER IST(6),LST(6)	!Start and stop positions.
       INTEGER N,L,I		!Counters.
       INTEGER L1,L2		!Fingers for the scan.
       INTEGER MSG		!Output unit.
       COMMON /IODEV/MSG	!Share.
Chop the text into words.
        N = 0		!No words found.
        L = LEN(TEXT)	!Multiple trailing spaces - no worries.
        L2 = 0		!Syncopation: where the previous chomp ended.
   10   L1 = L2		!Thus, where a fresh scan should follow.
   11   L1 = L1 + 1		!Advance one.
        IF (L1.GT.L) GO TO 20		!Finished yet?
        IF (TEXT(L1:L1).LE." ") GO TO 11	!No. Skip leading spaces.
        L2 = L1			!Righto, L1 is the first non-blank.
   12   L2 = L2 + 1		!Scan through the non-blanks.
        IF (L2.GT.L) GO TO 13	!Is it safe to look?
        IF (TEXT(L2:L2).GT." ") GO TO 12	!Yes. Speed through non-blanks.
   13   N = N + 1			!Righto, a word is found in TEXT(L1:L2 - 1)
        IST(N) = L1		!So, recall its first character.
        LST(N) = L2 - 1		!And its last.
        IF (L2.LT.L) GO TO 10	!Perhaps more text follows.
Comma time...
   20   WRITE (MSG,21) "{"	!Start the output.
   21   FORMAT (A,$)		!The $, obviously, specifies that the line is not finished.
        DO I = 1,N		!Step through the texts, there possibly being none.
          IF (I.GT.1) THEN		!If there has been a predecessor, supply separators.
            IF (I.LT.N) THEN			!Up to the last two, it's easy.
              WRITE (MSG,21) ", "			!Always just a comma.
            ELSE IF (OXFORDIAN) THEN		!But after the penultimate item, what?
              WRITE (MSG,21) ", and "			!Supply the comma omitted above: a double-power separator.
            ELSE				!One fewer comma, with possible ambiguity arising.
              WRITE (MSG,21) " and "			!A single separator.
            END IF				!So much for the style.
          END IF			!Enough with the separation.
          WRITE (MSG,21) TEXT(IST(I):LST(I))	!The text at last!
        END DO			!On to the next text.
        WRITE (MSG,"('}')")	!End the line, marking the end of the text.
      END		!That was fun.

      PROGRAM ENCOMMA	!Punctuate a list with commas.
      CHARACTER*(666) TEXT	!Holds the text. Easily long enough.
      INTEGER KBD,MSG,INF	!Now for some messing.
      COMMON /IODEV/MSG,KBD	!Pass the word.
      KBD = 5	!Standard input.
      MSG = 6	!Standard output.
      INF = 10	!Suitable for a disc file.
      OPEN (INF,FILE="List.txt",ACTION = "READ")	!Attach one.

   10 WRITE (MSG,11) "To insert commas into lists..."	!Announce.
   11 FORMAT (A)			!Just the text.
   12 READ (INF,11,END = 20) TEXT	!Grab the text, with trailing spaces to fill out TEXT.
      CALL QUIBBLE(TEXT,.FALSE.)	!One way to quibble.
      GO TO 12				!Try for another.

   20 REWIND (INF)			!Back to the start of the file.
      WRITE (MSG,11)			!Set off a bit.
      WRITE (MSG,11) "Oxford style..."	!Announce the proper style.
   21 READ (INF,11,END = 30) TEXT	!Grab the text.
      CALL QUIBBLE(TEXT,.TRUE.)		!The other way to quibble.
      GO TO 21				!Have another try.

Closedown
   30 END	!All files are closed by exiting.


(* this is a comment *)
(*
   and this is a
   multiline comment
   (* with a nested comment *)
*)


' FB 1.05.0 Win64

Sub Split(s As String, sep As String, result() As String)
  Dim As Integer i, j, count = 0
  Dim temp As String
  Dim As Integer position(Len(s) + 1)
  position(0) = 0
  For i = 0 To Len(s) - 1
    For j = 0 To Len(sep) - 1
      If s[i] = sep[j] Then
        count += 1
        position(count) = i + 1
      End If
    Next j
  Next i
  position(count + 1) = Len(s) + 1
  Redim result(count)
  For i = 1 To count + 1
    result(i - 1) = Mid(s, position(i - 1) + 1, position(i) - position(i - 1) - 1)
  Next
End Sub

Function CommaQuibble(s As String) As String
  Dim i As Integer
  Dim As String result
  Dim As String words()
  s = Trim(s, Any "[]""")
  ' Now remove internal quotes
  Split s, """", words()
  s = ""
  For i = 0 To UBound(words)
     s &= words(i)
  Next
  ' Now split 's' using the comma as separator
  Erase words
  Split s, ",", words()
  ' And re-assemble the string in the desired format
  result = "{"
  For i = 0 To UBound(words)
    If i = 0 Then
      result &= words(i)
    ElseIf i = UBound(words) Then
      result &= " and " & words(i)
    Else
      result &= ", " + words(i)
    EndIf
  Next
  Return result & "}"
End Function

' As 3 of the strings contain embedded quotes these need to be doubled in FB
Print CommaQuibble("[]")
Print CommaQuibble("[""ABC""]")
Print CommaQuibble("[""ABC"",""DEF""]")
Print CommaQuibble("[""ABC"",""DEF"",""G"",""H""]")
Print
Print "Press any key to quit the program"
Sleep


F perm(=n, p)
   BigInt r = 1
   V k = n - p
   L n > k
      r *= n--
   R r

F comb(n, =k)
   V r = perm(n, k)
   L k > 0
      r I/= k--
   R r

L(i) 1..11
   print(‘P(12,’i‘) = ’perm(12, i))
L(i) (10.<60).step(10)
   print(‘C(60,’i‘) = ’comb(60, i))


Public Sub Main()
Dim sInput As String[] = ["", "ABC", "ABC DEF", "ABC DEF G H"]
Dim sTemp As String

For Each sTemp In sInput
  Print sTemp & " = ";
  sTemp = Replace(sTemp, " ", ",")
  If RInStr(sTemp, ",") > 0 Then
    sTemp = Mid(sTemp, 1, RInStr(sTemp, ",") - 1) & " and " & Mid(sTemp, RInStr(sTemp, ",") + 1)
  End If
  sTemp = "{" & sTemp & "}"
  Print sTemp
Next

End


package main

import (
    "fmt"
    "strings"
)

func q(s []string) string {
    switch len(s) {
    case 0:
        return "{}"
    case 1:
        return "{" + s[0] + "}"
    case 2:
        return "{" + s[0] + " and " + s[1] + "}"
    default:
        return "{" +
            strings.Join(s[:len(s)-1], ", ") +
            " and " +
            s[len(s)-1] +
            "}"
    }
}

func main() {
    fmt.Println(q([]string{}))
    fmt.Println(q([]string{"ABC"}))
    fmt.Println(q([]string{"ABC", "DEF"}))
    fmt.Println(q([]string{"ABC", "DEF", "G", "H"}))
}


# -*- coding: utf-8 -*- #

COMMENT REQUIRED by "prelude_combinations_and_permutations.a68" CO
  MODE CPINT = #LONG# ~;
  MODE CPOUT = #LONG# ~; # the answer, can be REAL #
  MODE CPREAL = ~; # the answer, can be REAL #
  PROC cp fix value error = (#REF# CPARGS args)BOOL: ~;
#PROVIDES:#
# OP C = (CP~,CP~)CP~: ~ #
# OP P = (CP~,CP~)CP~: ~ #
END COMMENT

MODE CPARGS = STRUCT(CHAR name, #REF# CPINT n,k);

PRIO C = 8, P = 8; # should be 7.5, a priority between *,/ and **,SHL,SHR etc #

# I suspect there is a more reliable way of doing this using the Gamma Function approx #

OP P = (CPINT n, r)CPOUT: (
  IF n < r ORF r < 0 THEN IF NOT cp fix value error(CPARGS("P",n,r)) THEN stop FI FI;
  CPOUT out := 1;
# basically nPk = (n-r+1)(n-r+2)...(n-2)(n-1)n = n!/(n-r)! #
  FOR i FROM n-r+1 TO n DO out *:= i OD;
  out
);

OP P = (CPREAL n, r)CPREAL: # 'ln gamma' requires GSL library #
  exp(ln gamma(n+1)-ln gamma(n-r+1));

# basically nPk = (n-r+1)(n-r+2)...(n-2)(n-1)n = n!/(n-r)! #
COMMENT # alternate slower version #
OP P = (CPREAL n, r)CPREAL: ( # alternate slower version #
  IF n < r ORF r < 0 THEN IF NOT cp fix value error(CPARGS("P",ENTIER n,ENTIER r)) THEN stop FI FI;
  CPREAL out := 1;
# basically nPk = (n-r+1)(n-r+2)...(n-2)(n-1)n = n!/(n-r)! #
  CPREAL i := n-r+1;
  WHILE i <= n DO
    out*:= i;
# a crude check for underflow #
    IF i = i + 1 THEN IF NOT cp fix value error(CPARGS("P",ENTIER n,ENTIER r)) THEN stop FI FI;
    i+:=1
  OD;
  out
);
END COMMENT

# basically C(n,r) = nCk = nPk/r! = n!/(n-r)!/r! #
OP C = (CPINT n, r)CPOUT: (
  IF n < r ORF r < 0 THEN IF NOT cp fix value error(("C",n,r)) THEN stop FI FI;
  CPINT largest = ( r > n - r | r | n - r );
  CPINT smallest = n - largest;
  CPOUT out := 1;
  INT smaller fact := 2;
  FOR larger fact FROM largest+1 TO n DO
# try and prevent overflow, p.s. there must be a smarter way to do this #
#   Problems: loop stalls when 'smaller fact' is a largeish co prime #
    out *:= larger fact;
    WHILE smaller fact <= smallest ANDF out MOD smaller fact = 0 DO
      out OVERAB smaller fact;
      smaller fact +:= 1
    OD
  OD;
  out # EXIT with: n P r OVER r P r #
);

OP C = (CPREAL n, CPREAL r)CPREAL: # 'ln gamma' requires GSL library #
  exp(ln gamma(n+1)-ln gamma(n-r+1)-ln gamma(r+1));

# basically C(n,r) = nCk = nPk/r! = n!/(n-r)!/r! #
COMMENT # alternate slower version #
OP C = (CPREAL n, REAL r)CPREAL: (
  IF n < r ORF r < 0 THEN IF NOT cp fix value error(("C",ENTIER n,ENTIER r)) THEN stop FI FI;
  CPREAL largest = ( r > n - r | r | n - r );
  CPREAL smallest = n - largest;
  CPREAL out := 1;
  REAL smaller fact := 2;
  REAL larger fact := largest+1;
  WHILE larger fact <= n DO # todo: check underflow here #
# try and prevent overflow, p.s. there must be a smarter way to do this #
    out *:= larger fact;
    WHILE smaller fact <= smallest ANDF out > smaller fact DO
      out /:= smaller fact;
      smaller fact +:= 1
    OD;
    larger fact +:= 1
  OD;
  out # EXIT with: n P r OVER r P r #
);
END COMMENT

SKIP


quibble ws = "{" ++ quibbles ws ++ "}"
  where quibbles [] = ""
        quibbles [a] = a
        quibbles [a,b] = a ++ " and " ++ b
        quibbles (a:bs) = a ++ ", " ++ quibbles bs

main = mapM_ (putStrLn . quibble) $
  [[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]] ++
  (map words ["One two three four", "Me myself I", "Jack Jill", "Loner" ])


#include <gmp.h>

void perm(mpz_t out, int n, int k)
{
	mpz_set_ui(out, 1);
	k = n - k;
	while (n > k) mpz_mul_ui(out, out, n--);
}

void comb(mpz_t out, int n, int k)
{
	perm(out, n, k);
	while (k) mpz_divexact_ui(out, out, k--);
}

int main(void)
{
	mpz_t x;
	mpz_init(x);

	perm(x, 1000, 969);
	gmp_printf("P(1000,969) = %Zd\n", x);

	comb(x, 1000, 969);
	gmp_printf("C(1000,969) = %Zd\n", x);
	return 0;
}


#include <boost/multiprecision/gmp.hpp>
#include <iostream>

using namespace boost::multiprecision;

mpz_int p(uint n, uint p) {
    mpz_int r = 1;
    mpz_int k = n - p;
    while (n > k)
        r *= n--;
    return r;
}

mpz_int c(uint n, uint k) {
    mpz_int r = p(n, k);
    while (k)
        r /= k--;
    return r;
}

int main() {
    for (uint i = 1u; i < 12u; i++)
        std::cout << "P(12," << i << ") = " << p(12u, i) << std::endl;
    for (uint i = 10u; i < 60u; i += 10u)
        std::cout << "C(60," << i << ") = " << c(60u, i) << std::endl;

    return 0;
}


procedure main()
    every write(quibble([] | ["ABC"] | ["ABC","DEF"] | ["ABC","DEF","G","H"]))
end

procedure quibble(A)
    join := s := ""
    while s := pull(A)||join||s do join := if *join = 0 then " and " else ", "
    return "{"||s||"}"
end


quibLast2=: ' and ' joinstring (2 [email protected]<. #) {. ]
withoutLast2=: ([: # _2&}.) {. ]
quibble=: '{', '}' ,~ ', ' joinstring withoutLast2 , <@quibLast2


public class Quibbler {

	public static String quibble(String[] words) {
		String qText = "{";
		for(int wIndex = 0; wIndex < words.length; wIndex++) {
			qText += words[wIndex] + (wIndex == words.length-1 ? "" :
						  wIndex == words.length-2 ? " and " :
						  ", ";
		}
		qText += "}";
		return qText;
	}

	public static void main(String[] args) {
		System.out.println(quibble(new String[]{}));
		System.out.println(quibble(new String[]{"ABC"}));
		System.out.println(quibble(new String[]{"ABC", "DEF"}));
		System.out.println(quibble(new String[]{"ABC", "DEF", "G"}));
		System.out.println(quibble(new String[]{"ABC", "DEF", "G", "H"}));
	}
}


import std.stdio, std.mathspecial, std.range, std.algorithm,
       std.bigint, std.conv;

enum permutation = (in uint n, in uint k) pure =>
    reduce!q{a * b}(1.BigInt, iota(n - k + 1, n + 1));

enum combination = (in uint n, in uint k) pure =>
    n.permutation(k) / reduce!q{a * b}(1.BigInt, iota(1, k + 1));

enum bigPermutation = (in uint n, in uint k) =>
    exp(logGamma(n + 1) - logGamma(n - k + 1));

enum bigCombination = (in uint n, in uint k) =>
    exp(logGamma(n + 1) - logGamma(n - k + 1) - logGamma(k + 1));

void main() {
    12.permutation(9).writeln;
    12.bigPermutation(9).writeln;
    60.combination(53).writeln;
    145.bigPermutation(133).writeln;
    900.bigCombination(450).writeln;
    1_000.bigCombination(969).writeln;
    15_000.bigPermutation(73).writeln;
    15_000.bigPermutation(1185).writeln;
    writefln("%(%s\\\n%)", 15_000.permutation(74).text.chunks(50));
}


function quibble(words) {
  return "{" +
    words.slice(0, words.length-1).join(",") +
   (words.length > 1 ? " and " : "") +
   (words[words.length-1] || '') +
  "}";
}

[[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]].forEach(
  function(s) {
    console.log(quibble(s));
  }
);


def quibble:
  if length == 0 then ""
  elif length == 1 then .[0]
  else (.[0:length-1] | join(", ")) + " and " + .[length-1]
  end
  | "{" + . + "}";


defmodule Combinations_permutations do
  def perm(n, k), do: product(n - k + 1 .. n)

  def comb(n, k), do: div( perm(n, k), product(1 .. k) )

  defp product(a..b) when a>b, do: 1
  defp product(list), do: Enum.reduce(list, 1, fn n, acc -> n * acc end)

  def test do
    IO.puts "\nA sample of permutations from 1 to 12:"
    Enum.each(1..12, &show_perm(&1, div(&1, 3)))
    IO.puts "\nA sample of combinations from 10 to 60:"
    Enum.take_every(10..60, 10) |> Enum.each(&show_comb(&1, div(&1, 3)))
    IO.puts "\nA sample of permutations from 5 to 15000:"
    Enum.each([5,50,500,1000,5000,15000], &show_perm(&1, div(&1, 3)))
    IO.puts "\nA sample of combinations from 100 to 1000:"
    Enum.take_every(100..1000, 100) |> Enum.each(&show_comb(&1, div(&1, 3)))
  end

  defp show_perm(n, k), do: show_gen(n, k, "perm", &perm/2)

  defp show_comb(n, k), do: show_gen(n, k, "comb", &comb/2)

  defp show_gen(n, k, strfun, fun), do:
    IO.puts "#{strfun}(#{n}, #{k}) = #{show_big(fun.(n, k), 40)}"

  defp show_big(n, limit) do
    strn = to_string(n)
    if String.length(strn) < limit do
      strn
    else
      {shown, hidden} = String.split_at(strn, limit)
      "#{shown}... (#{String.length(hidden)} more digits)"
    end
  end
end

Combinations_permutations.test


-module(combinations_permutations).

-export([test/0]).

perm(N, K) ->
    product(lists:seq(N - K + 1, N)).

comb(N, K) ->
    perm(N, K) div product(lists:seq(1, K)).

product(List) ->
    lists:foldl(fun(N, Acc) -> N * Acc end, 1, List).

test() ->
    io:format("\nA sample of permutations from 1 to 12:\n"),
    [show_perm({N, N div 3}) || N <- lists:seq(1, 12)],
    io:format("\nA sample of combinations from 10 to 60:\n"),
    [show_comb({N, N div 3}) || N <- lists:seq(10, 60, 10)],
    io:format("\nA sample of permutations from 5 to 15000:\n"),
    [show_perm({N, N div 3}) || N <- [5,50,500,1000,5000,15000]],
    io:format("\nA sample of combinations from 100 to 1000:\n"),
    [show_comb({N, N div 3}) || N <- lists:seq(100, 1000, 100)],
    ok.

show_perm({N, K}) ->
    show_gen(N, K, "perm", fun perm/2).

show_comb({N, K}) ->
    show_gen(N, K, "comb", fun comb/2).

show_gen(N, K, StrFun, Fun) ->
    io:format("~s(~p, ~p) = ~s\n",[StrFun, N, K, show_big(Fun(N, K), 40)]).

show_big(N, Limit) ->
    StrN = integer_to_list(N),
    case length(StrN) < Limit of
        true ->
            StrN;
        false ->
            {Shown, Hidden} = lists:split(Limit, StrN),
            io_lib:format("~s... (~p more digits)", [Shown, length(Hidden)])
    end.


function quibble(arr::Array)
    if isempty(arr) rst = "" else rst = "$(arr[end])" end
    if length(arr) > 1 rst = join(arr[1:end-1], ", ") * " and " * rst end
    return "{" * rst * "}"
end

@show quibble([])
@show quibble(["ABC"])
@show quibble(["ABC", "DEF"])
@show quibble(["ABC", "DEF", "G", "H"])


// version 1.0.6

fun commaQuibble(s: String): String {
    val t = s.trim('[', ']').replace(" ", "").replace("\"", "")
    val words = t.split(',')
    val sb = StringBuilder("{")
    for (i in 0 until words.size) {
        sb.append(when (i) {
            0                -> ""
            words.lastIndex  -> " and "
            else             -> ", "
        })
        sb.append(words[i])
    }
    return sb.append("}").toString()
}

fun main(args: Array<String>) {
    val inputs = arrayOf(
        """[]""",
        """["ABC"]""",
        """["ABC", "DEF"]""",
        """["ABC", "DEF", "G", "H"]"""
    )
    for (input in inputs) println("${input.padEnd(24)}  ->  ${commaQuibble(input)}")
}


Function PermBig(x As Long, y As Long) As ULongint
    Dim As Long i
    Dim As Longint z = 1
    For i = x - y + 1 To x
        z = z * i
    Next i
    Return (z)
End Function

Function FactBig(x As Long) As ULongint
    Dim As Long i
    Dim As Longint z = 1
    For i = 2 To x
        z = z * i
    Next i
    Return (z)
End Function

Function CombBig(Byval x As Long, Byval y As Long) As Double
    If y > x Then
        Return (0)
    Elseif x = y Then
        Return (1)
    Else
        If x - y < y Then y = x - y
        Return (PermBig(x, y) / FactBig(y))
    End If
End Function

Dim As Long i, j
Print "-- Long Integer - Permutations - from 1 to 12"
For i = 1 To 12
    For j = 1 To i
        Print "P(" & i & "," & j & ")=" & Str(PermBig(i, j)) & "  ";
    Next j
    Print ""
Next i

Print Chr(10) & "-- Float integer - Combinations from 10 to 60"
For i = 10 To 60 Step 10
    For j = 1 To i Step i \ 5
        Print "C(" & i & "," & j & ")=" & Str(CombBig(i, j)) & "  ";
    Next j
    Print ""
Next i

Print Chr(10) & "-- Float integer - Permutations from 5000 to 15000"
For i = 5000 To 15000 Step 5000
    For j = 10 To 50 Step 20
        Print "P(" & i & "," & j & ")=" & Str(PermBig(i, j)) & "  ";
    Next j
    Print ""
Next i

Print Chr(10) & "-- Float integer - Combinations from 200 to 1000"
For i = 200 To 1000 Step 200
    For j = 20 To 100 Step 20
        Print "C(" & i & "," & j & ")=" & Str(CombBig(i, j)) & "  ";
    Next j
    Print ""
Next i
Sleep


#!/usr/bin/lasso9

local(collection =
	array(
		array,
		array("ABC"),
		array("ABC", "DEF"),
		array("ABC", "DEF", "G", "H")
	)
)

with words in #collection do {
	if(#words -> size > 1) => {
		local(last = #words -> last)
		#words -> removelast
		stdoutnl('{' + #words -> join(', ') + ' and ' + #last'}')
	else(#words -> size == 1)
		stdoutnl('{' + #words -> first + '}')
	else
		stdoutnl('{}')
	}

}


do
        read in$
        if in$ ="END" then wait
        w =wordCount( in$)
        select case w
            case 0
                o$ ="{}"
            case 1
                o$ ="{" +in$ +"}"
            case 2
                o$ ="{" +word$( in$, 1) +" and " +word$( in$, 2) +"}"
            case else
                o$ ="{"
                o$ =o$ +word$( in$, 1)
                for k =2 to w -1
                    o$ =o$ +", " +word$( in$, k)
                next k
                o$ =o$ +" and " +word$( in$, w) +"}"
        end select
        if w =1 then
            print "'"; in$; "'"; " held "; w; " word. "; tab( 30); o$
        else
            print "'"; in$; "'"; " held "; w; " words. "; tab( 30); o$
        end if
    loop until 0

    wait

    function wordCount( IN$)
        wordCount =1
        for i =1 to len( IN$)
            if mid$( IN$, i, 1) =" " then wordCount =wordCount +1
        next i
    end function

    end

    data ""                 'No input words.
    data "ABC"              'One input word.
    data "ABC DEF"          'Two words.
    data "ABC DEF G"        'Three words.
    data "ABC DEF G H"      'Four words.

    data "END"              'Sentinel for EOD.


package main

import (
	"fmt"
	"math/big"
)

func main() {
	var n, p int64
	fmt.Printf("A sample of permutations from 1 to 12:\n")
	for n = 1; n < 13; n++ {
		p = n / 3
		fmt.Printf("P(%d,%d) = %d\n", n, p, perm(big.NewInt(n), big.NewInt(p)))
	}
	fmt.Printf("\nA sample of combinations from 10 to 60:\n")
	for n = 10; n < 61; n += 10 {
		p = n / 3
		fmt.Printf("C(%d,%d) = %d\n", n, p, comb(big.NewInt(n), big.NewInt(p)))
	}
	fmt.Printf("\nA sample of permutations from 5 to 15000:\n")
	nArr := [...]int64{5, 50, 500, 1000, 5000, 15000}
	for _, n = range nArr {
		p = n / 3
		fmt.Printf("P(%d,%d) = %d\n", n, p, perm(big.NewInt(n), big.NewInt(p)))
	}
	fmt.Printf("\nA sample of combinations from 100 to 1000:\n")
	for n = 100; n < 1001; n += 100 {
		p = n / 3
		fmt.Printf("C(%d,%d) = %d\n", n, p, comb(big.NewInt(n), big.NewInt(p)))
	}
}

func fact(n *big.Int) *big.Int {
	if n.Sign() < 1 {
		return big.NewInt(0)
	}
	r := big.NewInt(1)
	i := big.NewInt(2)
	for i.Cmp(n) < 1 {
		r.Mul(r, i)
		i.Add(i, big.NewInt(1))
	}
	return r
}

func perm(n, k *big.Int) *big.Int {
	r := fact(n)
	r.Div(r, fact(n.Sub(n, k)))
	return r
}

func comb(n, r *big.Int) *big.Int {
	if r.Cmp(n) == 1 {
		return big.NewInt(0)
	}
	if r.Cmp(n) == 0 {
		return big.NewInt(1)
	}
	c := fact(n)
	den := fact(n.Sub(n, r))
	den.Mul(den, fact(r))
	c.Div(c, den)
	return c
}


to join :delimiter :list [:result []]
  output cond [
    [ [empty? :list]   :result ]
    [ [empty? :result] (join :delimiter butfirst :list first :list) ]
    [ else             (join :delimiter butfirst :list
                                        (word :result :delimiter first :list)) ]
  ]
end

to quibble :list
  local "length
  make "length count :list
  make "text (
    ifelse [:length <= 2] [
      (join "\ and\  :list)
    ] [
      (join "\ and\  (sentence join ",\  butlast :list last :list))
    ])
  output ifelse [empty? :text] "\{\} [(word "\{ :text "\})]
end

foreach [ [] [ABC] [ABC DEF] [ABC DEF G H] ] [
  print quibble ?
]

bye


function quibble (strTab)
    local outString, join = "{"
    for strNum = 1, #strTab do
        if strNum == #strTab then
            join = ""
        elseif strNum == #strTab - 1 then
            join = " and "
        else
            join = ", "
        end
        outString = outString .. strTab[strNum] .. join
    end
    return outString .. '}'
end

local testCases = {
    {},
    {"ABC"},
    {"ABC", "DEF"},
    {"ABC", "DEF", "G", "H"}
}
for _, input in pairs(testCases) do print(quibble(input)) end


perm :: Integer -> Integer -> Integer
perm n k = product [n-k+1..n]

comb :: Integer -> Integer -> Integer
comb n k = perm n k `div` product [1..k]

main :: IO ()
main = do
        let showBig maxlen b =
                let st = show b
                    stlen = length st
                in if stlen < maxlen then st else take maxlen st ++ "... ("  ++ show (stlen-maxlen) ++  " more digits)"

        let showPerm pr =
                putStrLn $ "perm(" ++ show n ++ "," ++ show k ++ ") = "  ++ showBig 40 (perm n k)
                where n = fst pr
                      k = snd pr

        let showComb pr =
                putStrLn $ "comb(" ++ show n ++ "," ++ show k ++ ") = "  ++ showBig 40 (comb n k)
                where n = fst pr
                      k = snd pr

        putStrLn "A sample of permutations from 1 to 12:"
        mapM_  showPerm [(n, n `div` 3) | n <- [1..12] ]

        putStrLn ""
        putStrLn "A sample of combinations from 10 to 60:"
        mapM_  showComb [(n, n `div` 3) | n <- [10,20..60] ]

        putStrLn ""
        putStrLn "A sample of permutations from 5 to 15000:"
        mapM_  showPerm [(n, n `div` 3) | n <- [5,50,500,1000,5000,15000] ]

        putStrLn ""
        putStrLn "A sample of combinations from 100 to 1000:"
        mapM_  showComb [(n, n `div` 3) | n <- [100,200..1000] ]


Module Checkit {
      function f$ {
            what$=mid$(trim$(letter$),2)
            what$=Left$(what$, len(what$)-1)
            flush ' erase any argument from stack
            Data param$(what$)
            m=stack.size
            document resp$="{"
             if m>2 then {
                  shift m-1, 2    ' get last two as first two
                  push letter$+" and "+letter$
                  m--   ' one less
                  shiftback m   ' move to last position
            }
            while not empty {
                   resp$=letter$+if$(not empty->", ", "")
             }
            =resp$+"}"

      }
      \\ we use ? for Print
      ? f$({[]})
      ? f$({["ABC"]})
      ? f$({["ABC", "DEF"]})
      ? f$({["ABC","DEF", "G", "H"]})
}
Checkit


Quibble := proc( los )
  uses  StringTools;
  Fence( proc()
        if los = [] then
          ""
        elif numelems( los ) = 1 then
          los[ 1 ]
        else
          cat( Join( los[ 1 .. -2 ], ", " ), " and ", los[ -1 ] )
        end if
  end(), "{", "}" )
end proc:


quibble[words___] :=
    [email protected]{[email protected]@
        Replace[Riffle[{words}, ", "],
            {most__, ", ", last_} -> {most, " and ", last}]}


function r = comma_quibbling(varargin)
	if isempty(varargin)
		r = '';
	elseif length(varargin)==1;
		r = varargin{1};
	else
		r = [varargin{end-1},' and ', varargin{end}];
		for k=length(varargin)-2:-1:1,
			r = [varargin{k}, ', ', r];
		end
	end
end;


fn separate words: =
(
	if words == unsupplied or words == undefined or classof words != array then return "{}"
		else
		(
			local toReturn = "{"
			local pos = 1
			while pos <= words.count do
			(
				if pos == 1 then (append toReturn words[pos]; pos+=1)
				else
				(
					if pos <= words.count-1 then (append toReturn (", "+words[pos]); pos+=1)
						else
						(
							append toReturn (" and " + words[pos])
							pos +=1
						)
				)
			)
			return (toReturn+"}")
		)
)


import java.math.BigInteger;

public class CombinationsAndPermutations {

    public static void main(String[] args) {
        System.out.println(Double.MAX_VALUE);
        System.out.println("A sample of permutations from 1 to 12 with exact Integer arithmetic:");
        for ( int n = 1 ; n <= 12 ; n++ ) {
            int k = n / 2;
            System.out.printf("%d P %d = %s%n", n, k, permutation(n, k));
        }

        System.out.println();
        System.out.println("A sample of combinations from 10 to 60 with exact Integer arithmetic:");
        for ( int n = 10 ; n <= 60 ; n += 5 ) {
            int k = n / 2;
            System.out.printf("%d C %d = %s%n", n, k, combination(n, k));
        }

        System.out.println();
        System.out.println("A sample of permutations from 5 to 15000 displayed in floating point arithmetic:");
        System.out.printf("%d P %d = %s%n", 5, 2, display(permutation(5, 2), 50));
        for ( int n = 1000 ; n <= 15000 ; n += 1000 ) {
            int k = n / 2;
            System.out.printf("%d P %d = %s%n", n, k, display(permutation(n, k), 50));
        }

        System.out.println();
        System.out.println("A sample of combinations from 100 to 1000 displayed in floating point arithmetic:");
        for ( int n = 100 ; n <= 1000 ; n += 100 ) {
            int k = n / 2;
            System.out.printf("%d C %d = %s%n", n, k, display(combination(n, k), 50));
        }

    }

    private static String display(BigInteger val, int precision) {
        String s = val.toString();
        precision = Math.min(precision, s.length());
        StringBuilder sb = new StringBuilder();
        sb.append(s.substring(0, 1));
        sb.append(".");
        sb.append(s.substring(1, precision));
        sb.append(" * 10^");
        sb.append(s.length()-1);
        return sb.toString();
    }

    public static BigInteger combination(int n, int k) {
        //  Select value with smallest intermediate results
        //    combination(n, k) = combination(n, n-k)
        if ( n-k < k ) {
            k = n-k;
        }
        BigInteger result = permutation(n, k);
        while ( k > 0 ) {
            result = result.divide(BigInteger.valueOf(k));
            k--;
        }
        return result;
    }

    public static BigInteger permutation(int n, int k) {
        BigInteger result = BigInteger.ONE;
        for ( int i = n ; i >= n-k+1 ; i-- ) {
            result = result.multiply(BigInteger.valueOf(i));
        }
        return result;
    }

}


/* NetRexx */
options replace format comments java crossref symbols nobinary

runSample(arg)
return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method quibble(arg) public static
  parse arg '[' lst ']'
  lst = lst.changestr('"', '').space(1)
  lc = lst.lastpos(',')
  if lc > 0 then
    lst = lst.insert('and', lc).overlay(' ', lc)
  return '{'lst'}'

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
  lists = ['[]', -                     -- {}
           '["ABC"]', -                -- {ABC}
           '["ABC", "DEF"]', -         -- {ABC and DEF}
           '["ABC", "DEF", "G", "H"]'] -- {ABC, DEF, G and H}
  loop lst over lists
    say lst.right(30) ':' quibble(lst)
    end lst
  return


proc commaQuibble(s: openArray[string]): string =
  result = ""
  for i, c in s:
    if i > 0: result.add (if i < s.high: ", " else: " and ")
    result.add c
  result = "{" & result & "}"

var s = @[@[], @["ABC"], @["ABC", "DEF"], @["ABC", "DEF", "G", "H"]]
for i in s:
  echo commaQuibble(i)


def permutation(k): . as $n
  | reduce range($n-k+1; 1+$n) as $i (1; . * $i);

def combination(k): . as $n
  | if k > ($n/2) then combination($n-k)
    else reduce range(0; k) as $i (1; (. * ($n - $i)) / ($i + 1))
    end;

# natural log of n!
def log_factorial: (1+.) | tgamma | log;

def log_permutation(k):
  (log_factorial - ((.-k) | log_factorial));

def log_combination(k):
  (log_factorial - ((. - k)|log_factorial) - (k|log_factorial));

def big_permutation(k): log_permutation(k) | exp;

def big_combination(k): log_combination(k) | exp;


function Base.binomial{T<:FloatingPoint}(n::T, k::T)
    exp(lfact(n) - lfact(n - k) - lfact(k))
end

function Base.factorial{T<:FloatingPoint}(n::T, k::T)
    exp(lfact(n) - lfact(k))
end

⊞{T<:Real}(n::T, k::T) = binomial(n, k)
⊠{T<:Real}(n::T, k::T) = factorial(n, n-k)


// version 1.1.2

import java.math.BigInteger

fun perm(n: Int, k: Int): BigInteger {
    require(n > 0 && k >= 0)
    return (n - k + 1 .. n).fold(BigInteger.ONE) { acc, i -> acc * BigInteger.valueOf(i.toLong()) }
}

fun comb(n: Int, k: Int): BigInteger {
    require(n > 0 && k >= 0)
    val fact = (2..k).fold(BigInteger.ONE) { acc, i -> acc * BigInteger.valueOf(i.toLong()) }
    return perm(n, k) / fact
}

fun main(args: Array<String>) {
    println("A sample of permutations from 1 to 12:")
    for (n in 1..12) System.out.printf("%2d P %-2d = %d\n", n, n / 3, perm(n, n / 3))

    println("\nA sample of combinations from 10 to 60:")
    for (n in 10..60 step 10) System.out.printf("%2d C %-2d = %d\n", n, n / 3, comb(n, n / 3))

    println("\nA sample of permutations from 5 to 15000:")
    val na = intArrayOf(5, 50, 500, 1000, 5000, 15000)
    for (n in na) {
        val k = n / 3
        val s = perm(n, k).toString()
        val l = s.length
        val e = if (l <= 40) "" else "... (${l - 40} more digits)"
        System.out.printf("%5d P %-4d = %s%s\n", n, k, s.take(40), e)
    }

    println("\nA sample of combinations from 100 to 1000:")
    for (n in 100..1000 step 100) {
        val k = n / 3
        val s = comb(n, k).toString()
        val l = s.length
        val e = if (l <= 40) "" else "... (${l - 40} more digits)"
        System.out.printf("%4d C %-3d = %s%s\n", n, k, s.take(40), e)
    }
}


MODULE CommaQuibbling;
IMPORT
  NPCT:Args,
  Strings,
  Out;

VAR
  str: ARRAY 256 OF CHAR;

  PROCEDURE Do(VAR s: ARRAY OF CHAR);
  VAR
    aux: ARRAY 128 OF CHAR;
    i,params: LONGINT;
  BEGIN
    params := Args.Number() - 1;
    CASE params OF
       0:
        COPY("{}",s)
      |1:
        Args.At(1,aux);
        Strings.Append("{",s);
        Strings.Append(aux,s);
        Strings.Append("}",s);
      ELSE
        Strings.Append("{",s);
        FOR i := 1 TO params - 1 DO
          Args.At(i,aux);
          Strings.Append(aux,s);
          IF i # params - 1 THEN
            Strings.Append(", ",s)
          ELSE
            Strings.Append(" and ", s)
          END
        END;
        Args.At(params,aux);
        Strings.Append(aux,s);
        Strings.Append("}",s)
    END;

  END Do;

BEGIN
  Do(str);
  Out.String(":> ");Out.String(str);Out.Ln
END CommaQuibbling.


class Quibbler {
  function : Quibble(words : String[]) ~ String {
    text := "{";

    each(i : words) {
      text += words[i];
      if(i < words->Size() - 2) {
        text += ", ";
      }
      else if(i = words->Size() - 2) {
        text += " and ";
      };
    };
    text += "}";

    return text;
  }

  function : Main(args : String[]) ~ Nil {
    words := String->New[0];
    Quibble(words)->PrintLine();

    words := ["ABC"];
    Quibble(words)->PrintLine();

    words := ["ABC", "DEF"];
    Quibble(words)->PrintLine();

    words := ["ABC", "DEF", "G", "H"];
    Quibble(words)->PrintLine();
  }
}


Module PermComb {
      Form 80, 50
      perm=lambda (x,y) ->{
            def i,z
            z=1
            For i=x-y+1 to x :z*=i:next i
           =z
      }
      fact=lambda (x) ->{
            def i,z
            z=1
            For i=2 to x :z*=i:next i
            =z
      }
      comb=lambda  (x as decimal, y as decimal) ->{
            If y>x then {
                  =0
            } else.if x=y then  {
                  =1
            } else {
                  if x-y<y then y=x-y
                  def decimal  i, z=1, ym
                  ym=y
                  For i=x to x-y+1
                        z*=i
                        z=z/ym
                       ym-- : if ym<1 then [email protected]
                  next  i
                  =round(z,0)

            }
      }
      Document Doc$
      WriteLn("-- Permutations - from 1 to 12")
      For i=1 to 12
      l$="" : For j=1 to i : l$+= format$("P({0},{1})={2}  ",i, j,perm(i, j)) :next j
      Writetext(l$)
      next i
      WriteLn("-- Combinations from 10 to 60")
      For i=10  to 60 step 10
      l$="" : For j=1 to i step i div 5 : l$+= format$("C({0},{1})={2}  ",i, j,comb(i, j)) :next j
      Writetext(l$)
      Next i
      WriteLn("-- Permutations from 5000 to 15000")
      For i=5000 to 15000 step 5000
      l$="" : For j=10 to 70  step  20: l$+= format$("P({0},{1})={2}  ",i, j,perm(i, j)) :next j
      Writetext(l$)
      Next i
      WriteLn("-- Combinations from 200 to 1000")
      For i=200 to 1000 step 200
      l$="" : For j=20 to 100 step 20: l$+= format$("C({0},{1})={2}  ",i, j,comb(i, j)) :next j
      Writetext(l$)
      Next i
      ClipBoard Doc$
      Sub WriteText(a$)
      doc$=a$+{
      }
      Report a$
      End Sub
      Sub WriteLn(a$)
      doc$=a$+{
      }
      Print a$
      End Sub
}
PermComb


comb := proc (n::integer, k::integer)
    return factorial(n)/(factorial(k)*factorial(n-k));
end proc;
perm := proc (n::integer, k::integer)
    return factorial(n)/factorial(n-k);
end proc;


П2	<->	П1	->	<->	П7	КПП7	С/П
ИП1	ИП2	-	ПП	53	П3	ИП1	ПП	53	ИП3	/	В/О
1	ИП1	*	L2	21	В/О
ИП1	ИП2	-	ПП	53	П3	ИП2	ПП	53	ИП3	*	П3	ИП1	ПП	53	ИП3	/	В/О
ИП1	ИП2	+	1	-	П1	ПП	26	В/О
ВП    П0    1    ИП0    *    L0    56    В/О


open Printf

let quibble list =
  let rec aux = function
    | a :: b :: c :: d :: rest -> a ^ ", " ^ aux (b :: c :: d :: rest)
    | [a; b; c] -> sprintf "%s, %s and %s}" a b c
    | [a; b] -> sprintf "%s and %s}" a b
    | [a] -> sprintf "%s}" a
    | [] -> "}" in
  "{" ^ aux list

let test () =
  [[];
   ["ABC"];
   ["ABC"; "DEF"];
   ["ABC"; "DEF"; "G"; "H"]]
  |> List.iter (fun list -> print_endline (quibble list))


: quibbing(l) -- string
| i s |
   StringBuffer new "{" <<
   l size dup 1- ->s loop: i [
      l at(i) <<
      i s < ifTrue: [ ", " << continue ]
      i s == ifTrue: [ " and " << ]
      ]
   "}" << dup freeze ;


import bigints

proc perm(n, k: int32): BigInt =
  result = initBigInt 1
  var
    k = n - k
    n = n
  while n > k:
    result *= n
    dec n

proc comb(n, k: int32): BigInt =
  result = perm(n, k)
  var k = k
  while k > 0:
    result = result div k
    dec k

echo "P(1000, 969) = ", perm(1000, 969)
echo "C(1000, 969) = ", comb(1000, 969)


sample(f,a,b)=for(i=1,4, my(n1=random(b-a)+a,n2=random(b-a)+a); [n1,n2]=[max(n1,n2),min(n1,n2)]; print(n1", "n2": "f(n1,n2)))
permExact(m,n)=factorback([m-n+1..m]);
combExact=binomial;
permApprox(m,n)=exp(lngamma(m+1)-lngamma(m-n+1));
combApprox(m,n)=exp(lngamma(m+1)-lngamma(n+1)-lngamma(m-n+1));

sample(permExact, 1, 12);
sample(combExact, 10, 60);
sample(permApprox, 5, 15000);
sample(combApprox, 100, 1000);


(define (quibble . args)
   (display "{")
   (let loop ((args args))
      (unless (null? args) (begin
         (display (car args))
         (cond
            ((= 1 (length args)) #t)
            ((= 2 (length args))
               (display " and "))
            (else
               (display ", ")))
         (loop (cdr args)))))
   (print "}"))

; testing =>
(quibble)
(quibble "ABC")
(quibble "ABC" "DEF")
(quibble "ABC" "DEF" "G" "H")


program CommaQuibbling;

uses
  SysUtils,
  Classes,
  StrUtils;

const
  OuterBracket =['[', ']'];

type

{$IFNDEF FPC}
  SizeInt = LongInt;
{$ENDIF}

  { TCommaQuibble }

  TCommaQuibble = class(TStringList)
  private
    function GetCommaquibble: string;
    procedure SetCommaQuibble(AValue: string);
  public
    property CommaQuibble: string read GetCommaquibble write SetCommaQuibble;
  end;

{$IFNDEF FPC} // Delphi support

function WordPosition(const N: Integer; const S: string; const WordDelims:
  TSysCharSet): SizeInt;
var
  PS, P, PE: PChar;
  Count: Integer;
begin
  Result := 0;
  Count := 0;
  PS := PChar(pointer(S));
  PE := PS + Length(S);
  P := PS;
  while (P < PE) and (Count <> N) do
  begin
    while (P < PE) and (P^ in WordDelims) do
      inc(P);
    if (P < PE) then
      inc(Count);
    if (Count <> N) then
      while (P < PE) and not (P^ in WordDelims) do
        inc(P)
    else
      Result := (P - PS) + 1;
  end;
end;

function ExtractWordPos(N: Integer; const S: string; const WordDelims:
  TSysCharSet; out Pos: Integer): string;
var
  i, j, l: SizeInt;
begin
  j := 0;
  i := WordPosition(N, S, WordDelims);
  if (i > High(Integer)) then
  begin
    Result := '';
    Pos := -1;
    Exit;
  end;
  Pos := i;
  if (i <> 0) then
  begin
    j := i;
    l := Length(S);
    while (j <= l) and not (S[j] in WordDelims) do
      inc(j);
  end;
  SetLength(Result, j - i);
  if ((j - i) > 0) then
    Result := copy(S, i, j - i);
end;

function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet):
  string; inline;
var
  i: SizeInt;
begin
  Result := ExtractWordPos(N, S, WordDelims, i);
end;
{$ENDIF}

{ TCommaQuibble }

procedure TCommaQuibble.SetCommaQuibble(AValue: string);
begin
  AValue := ExtractWord(1, AValue, OuterBracket);
  commatext := AValue;
end;

function TCommaQuibble.GetCommaquibble: string;
var
  x: Integer;
  Del: string;
begin
  result := '';
  Del := ', ';
  for x := 0 to Count - 1 do
  begin
    result := result + Strings[x];
    if x = Count - 2 then
      Del := ' and '
    else if x = Count - 1 then
      Del := '';
    result := result + Del;
  end;
  result := '{' + result + '}';
end;

const
  TestData: array[0..7] of string = ('[]', '["ABC"]', '["ABC", "DEF"]',
    '["ABC", "DEF", "G", "H"]', '', '"ABC"', '"ABC", "DEF"', '"ABC", "DEF", "G", "H"');

var
  Quibble: TCommaQuibble;
  TestString: string;

begin
  Quibble := TCommaQuibble.Create;

  for TestString in TestData do
  begin
    Quibble.CommaQuibble := TestString;
    writeln(Quibble.CommaQuibble);
  end;
end.


with javascript_semantics
function P(integer n,k)
    return factorial(n)/factorial(n-k)
end function

function C(integer n,k)
    return P(n,k)/factorial(k)
end function

function lstirling(atom n)
    if n<10 then
        return lstirling(n+1)-log(n+1)
    end if
    return 0.5*log(2*PI*n) + n*log(n/E + 1/(12*E*n))
end function

function P_approx(integer n, k)
    return lstirling(n)-lstirling(n-k)
end function

function C_approx(integer n, k)
    return lstirling(n)-lstirling(n-k)-lstirling(k)
end function

function to_s(atom v)
integer e = floor(v/log(10))
    return sprintf("%.9ge%d",{power(E,v-e*log(10)),e})
end function

-- Test code

printf(1,"=> Exact results:\n")
for n=1 to 12 do
    integer p = floor(n/3)
    printf(1,"P(%d,%d) = %d\n",{n,p,P(n,p)})
end for

for n=10 to 60 by 10 do
    integer p = floor(n/3)
    printf(1,"C(%d,%d) = %d\n",{n,p,C(n,p)})
end for

printf(1,"=> Floating point approximations:\n")
constant tests = {5, 50, 500, 1000, 5000, 15000}
for i=1 to length(tests) do
    integer n=tests[i], p = floor(n/3)
    printf(1,"P(%d,%d) = %s\n",{n,p,to_s(P_approx(n,p))})
end for

for n=100 to 1000 by 100 do
    integer p = floor(n/3)
    printf(1,"C(%d,%d) = %s\n",{n,p,to_s(C_approx(n,p))})
end for


sub comma_quibbling(@) {
    return "{$_}" for
        @_ < 2 ? "@_" :
        join(', ', @_[0..@_-2]) . ' and ' . $_[-1];
}

print comma_quibbling(@$_), "\n" for
    [], [qw(ABC)], [qw(ABC DEF)], [qw(ABC DEF G H)];


function quibble(sequence words)
    if length(words)>=2 then
        words[-2..-1] = {words[-2]&" and "&words[-1]}
    end if
    return "{"&join(words,", ")&"}"
end function

constant tests = {{},
                  {"ABC"},
                  {"ABC","DEF"},
                  {"ABC","DEF","G","H"}}

for i=1 to length(tests) do
    ?quibble(tests[i])
end for


from __future__ import print_function

from scipy.misc import factorial as fact
from scipy.misc import comb

def perm(N, k, exact=0):
    return comb(N, k, exact) * fact(k, exact)

exact=True
print('Sample Perms 1..12')
for N in range(1, 13):
    k = max(N-2, 1)
    print('%iP%i =' % (N, k), perm(N, k, exact), end=', ' if N % 5 else '\n')

print('\n\nSample Combs 10..60')
for N in range(10, 61, 10):
    k = N-2
    print('%iC%i =' % (N, k), comb(N, k, exact), end=', ' if N % 50 else '\n')

exact=False
print('\n\nSample Perms 5..1500 Using FP approximations')
for N in [5, 15, 150, 1500, 15000]:
    k = N-2
    print('%iP%i =' % (N, k), perm(N, k, exact))

print('\nSample Combs 100..1000 Using FP approximations')
for N in range(100, 1001, 100):
    k = N-2
    print('%iC%i =' % (N, k), comb(N, k, exact))


<?php

function quibble($arr){

  $words = count($arr);

  if($words == 0){
    return '{}';
  }elseif($words == 1){
    return '{'.$arr[0].'}';
  }elseif($words == 2){
    return '{'.$arr[0].' and '.$arr[1].'}';
  }else{
    return '{'.implode(', ',  array_splice($arr, 0, -1) ). ' and '.$arr[0].'}';
  }

}

$tests = [
  [],
  ["ABC"],
  ["ABC", "DEF"],
  ["ABC", "DEF", "G", "H"]
];

foreach ($tests as $test) {
  echo quibble($test) . PHP_EOL;
}


perm <- function(n, k) choose(n, k) * factorial(k)
print(perm(seq(from = 3, to = 12, by = 3), seq(from = 2, to = 8, by = 2)))
print(choose(seq(from = 10, to = 60, by = 10), seq(from = 3, to = 18, by = 3)))
print(perm(seq(from = 1500, to = 15000, by = 1500), seq(from = 55, to = 100, by = 5)))
print(choose(seq(from = 100, to = 1000, by = 150), seq(from = 70, to = 100, by = 5)))


multi P($n, $k) { [*] $n - $k + 1 .. $n }
multi C($n, $k) { P($n, $k) / [*] 1 .. $k }

sub lstirling(\n) {
    n < 10 ?? lstirling(n+1) - log(n+1) !!
    .5*log(2*pi*n)+ n*log(n/e+1/(12*e*n))
}

role Logarithm {
    method gist {
	my $e = (self/10.log).Int;
	sprintf "%.8fE%+d", exp(self - $e*10.log), $e;
    }
}
multi P($n, $k, :$float!) {
    (lstirling($n) - lstirling($n -$k))
    but Logarithm
}
multi C($n, $k, :$float!) {
    (lstirling($n) - lstirling($n -$k) - lstirling($k))
    but Logarithm
}

say "Exact results:";
for 1..12 -> $n {
    my $p = $n div 3;
    say "P($n, $p) = ", P($n, $p);
}

for 10, 20 ... 60 -> $n {
    my $p = $n div 3;
    say "C($n, $p) = ", C($n, $p);
}

say '';
say "Floating point approximations:";
for 5, 50, 500, 1000, 5000, 15000 -> $n {
    my $p = $n div 3;
    say "P($n, $p) = ", P($n, $p, :float);
}

for 100, 200 ... 1000 -> $n {
    my $p = $n div 3;
    say "C($n, $p) = ", C($n, $p, :float);
}


100H:

/* COPY A STRING (MINUS TERMINATOR), RETURNS LENGTH (MINUS TERMINATOR) */
COPY$STR: PROCEDURE(SRC, DST) ADDRESS;
    DECLARE (SRC, DST) ADDRESS;
    DECLARE (SCH BASED SRC, DCH BASED DST) BYTE;
    DECLARE L ADDRESS;
    L = 0;
    DO WHILE SCH <> '$';
        DCH = SCH;
        SRC = SRC + 1;
        DST = DST + 1;
        L = L + 1;
    END;
    RETURN L;
END COPY$STR;

/* QUIBBLE GIVEN ARRAY OF $-TERMINATED STRINGS, STORE RESULT IN BUFR */
QUIBBLE: PROCEDURE(WORDS, BUFR) ADDRESS;
    DECLARE (WORDS, BUFR, ADR) ADDRESS;
    DECLARE (WORD BASED WORDS, WPTR) ADDRESS;
    DECLARE (WCHAR BASED WPTR, BCHAR BASED BUFR) BYTE;

    /* BRACES AND LOWERCASE LETTERS ARE NOT WITHIN PL/M CHARSET */
    DECLARE LBRACE LITERALLY '123', RBRACE LITERALLY '125';
    DECLARE ANDSTR DATA (32,97,110,100,32,'$');

    ADR = BUFR;
    BCHAR = LBRACE;
    BUFR = BUFR + 1;
    DO WHILE WORD <> 0;
        BUFR = BUFR + COPY$STR(WORD, BUFR);
        WORDS = WORDS + 2;
        IF WORD <> 0 THEN
            IF WORD(1) <> 0 THEN
                BUFR = BUFR + COPY$STR(.', $', BUFR);
            ELSE
                BUFR = BUFR + COPY$STR(.ANDSTR, BUFR);
    END;
    BCHAR = RBRACE;
    BUFR = BUFR + 1;
    BCHAR = '$';
    RETURN ADR;
END QUIBBLE;

/* --- CP/M OUTPUT AND TESTING --- */
BDOS: PROCEDURE(FUNC, ARG); /* MAKE CP/M SYSTEM CALL */
    DECLARE FUNC BYTE, ARG ADDRESS;
    GO TO 5;
END BDOS;

DECLARE BDOS$EXIT LITERALLY '0',  /* EXIT TO CP/M */
        BDOS$PUTS LITERALLY '9';  /* PRINT STRING */

PUTS: PROCEDURE(S);
    DECLARE S ADDRESS;
    CALL BDOS(BDOS$PUTS, S);
    CALL BDOS(BDOS$PUTS, .(13,10,'$'));
END PUTS;

/* ARRAY WITH INITIALLY NO CONTENTS */
DECLARE ARR (5) ADDRESS INITIAL (0,0,0,0,0);

CALL PUTS(QUIBBLE(.ARR, .MEMORY)); /* NO STRINGS */
ARR(0) = .'ABC$';
CALL PUTS(QUIBBLE(.ARR, .MEMORY)); /* ABC */
ARR(1) = .'DEF$';
CALL PUTS(QUIBBLE(.ARR, .MEMORY)); /* ABC AND DEF */
ARR(2) = .'G$';
ARR(3) = .'H$';
CALL PUTS(QUIBBLE(.ARR, .MEMORY)); /* ABC, DEF, G AND H */

CALL BDOS(BDOS$EXIT, 0);
EOF


To quibble four words:
Add "ABC" to some string things.
Add "DEF" to the string things.
Add "G" to the string things.
Add "H" to the string things.
Quibble the string things.

To quibble one word:
Add "ABC" to some string things.
Quibble the string things.

To quibble some string things:
Quibble the string things giving a string.
Destroy the string things.
Write the string on the console.

To quibble some string things giving a string:
Append "{" to the string.
Put the string things' count into a count.
If the count is 0, append "}" to the string; exit.
Get a string thing from the string things.
If the count is 1, append the string thing's string then "}" to the string; exit.
Loop.
If a counter is past the count minus 2, append the string thing's string then " and " then the string thing's next's string then "}" to the string; exit.
Append the string thing's string then ", " to the string.
Put the string thing's next into the string thing.
Repeat.

To quibble two words:
Add "ABC" to some string things.
Add "DEF" to the string things.
Quibble the string things.

To quibble zero words:
Quibble some string things.

To run:
Start up.
Quibble zero words.
Quibble one word.
Quibble two words.
Quibble four words.
Wait for the escape key.
Shut down.


/*REXX program  compute and displays  a sampling of  combinations  and  permutations.   */
numeric digits 100                               /*use 100 decimal digits of precision. */

      do      j=1  for  12;                _=    /*show all permutations from  1 ──► 12.*/
           do k=1  for   j                       /*step through all  J  permutations.   */
           _=_  'P('j","k')='perm(j,k)" "        /*add an extra blank between numbers.  */
           end       /*k*/
      say strip(_)                               /*show the permutations horizontally.  */
      end           /*j*/
say                                              /*display a blank line for readability.*/
      do      j=10  to  60  by 10;         _=    /*show some combinations  10 ──►  60.  */
           do k= 1  to   j  by j%5               /*step through some combinations.      */
           _=_  'C('j","k')='comb(j,k)" "        /*add an extra blank between numbers.  */
           end   /*k*/
      say strip(_)                               /*show the combinations horizontally.  */
      end           /*j*/
say                                              /*display a blank line for readability.*/
numeric digits 20                                /*force floating point for big numbers.*/

      do      j=5  to 15000      by 1000;  _=    /*show a few permutations, big numbers.*/
           do k=1  to  j  for 5  by j%10         /*step through some  J  permutations.  */
           _=_  'P('j","k')='perm(j,k)" "        /*add an extra blank between numbers.  */
           end      /*k*/
      say strip(_)                               /*show the permutations horizontally.  */
      end           /*j*/
say                                              /*display a blank line for readability.*/
      do      j=100  to 1000  by 100;      _=    /*show a few combinations, big numbers.*/
           do k=  1  to    j  by j%5             /*step through some combinations.      */
           _=_  'C('j","k')='comb(j,k)" "        /*add an extra blank between numbers.  */
           end      /*k*/
      say strip(_)                               /*show the combinations horizontally.  */
      end           /*j*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
perm:      procedure; parse arg x,y;      call .combPerm;                         return _
.combPerm:                          _=1;    do j=x-y+1  to x;    _=_*j;  end;     return _
!:         procedure; parse arg x;  !=1;    do j=2      to x;    !=!*j;  end;     return !
/*──────────────────────────────────────────────────────────────────────────────────────*/
comb:      procedure; parse arg x,y              /*arguments:  X  things,  Y  at-a-time.*/
                      if y   >x   then return 0  /*oops-say, an error,  too big a chunk.*/
                      if x   =y   then return 1  /*X  things are the same as chunk size.*/
                      if x-y <y   then y=x - y   /*switch things around for speed.      */
                      call .combPerm             /*call subroutine to do heavy lifting. */
                      return _ / !(y)            /*just perform one last division.      */


function Out-Quibble
{
    [OutputType([string])]
    Param
    (
        # Zero or more strings.
        [Parameter(Mandatory=$false, Position=0)]
        [AllowEmptyString()]
        [string[]]
        $Text = ""
    )

    # If not null or empty...
    if ($Text)
    {
        # Remove empty strings from the array.
        $text = "$Text".Split(" ", [StringSplitOptions]::RemoveEmptyEntries)
    }
    else
    {
        return "{}"
    }

    # Build a format string.
    $outStr = ""
    for ($i = 0; $i -lt $text.Count; $i++)
    {
        $outStr += "{$i}, "
    }
    $outStr = $outStr.TrimEnd(", ")

    # If more than one word, insert " and" at last comma position.
    if ($text.Count -gt 1)
    {
        $cIndex = $outStr.LastIndexOf(",")
        $outStr = $outStr.Remove($cIndex,1).Insert($cIndex," and")
    }

    # Output the formatted string.
    "{" + $outStr -f $text + "}"
}


words_series(Words, Bracketed) :-
    words_serialized(Words, Serialized),
    atomics_to_string(["{",Serialized,"}"], Bracketed).

words_serialized([], "").
words_serialized([Word], Word) :- !.
words_serialized(Words, Serialized) :-
    append(Rest, [Last], Words),                                  %% Splits the list of *Words* into the *Last* word and the *Rest*
    atomics_to_string(Rest, ", ", WithCommas),
    atomics_to_string([WithCommas, " and ", Last], Serialized).

test :-
    forall( member(Words, [[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]]),
            ( words_series(Words, Series),
              format('~w ~15|=> ~w~n', [Words, Series]))
          ).


(define (combinations n k)
  (do ((i 0 (+ 1 i))
       (res 1 (/ (* res (- n i))
                 (- k i))))
    ((= i k) res)))

(define (permutations n k)
  (do ((i 0 (+ 1 i))
       (res 1 (* res (- n i))))
    ((= i k) res)))

(display "P(4,2) = ") (display (permutations 4 2)) (newline)
(display "P(8,2) = ") (display (permutations 8 2)) (newline)
(display "P(10,8) = ") (display (permutations 10 8)) (newline)
(display "C(10,8) = ") (display (combinations 10 8)) (newline)
(display "C(20,8) = ") (display (combinations 20 8)) (newline)
(display "C(60,58) = ") (display (combinations 60 58)) (newline)
(display "P(1000,10) = ") (display (permutations 1000 10)) (newline)
(display "P(1000,20) = ") (display (permutations 1000 20)) (newline)
(display "P(15000,2) = ") (display (permutations 15000 3)) (newline)
(display "C(1000,10) = ") (display (combinations 1000 10)) (newline)
(display "C(1000,999) = ") (display (combinations 1000 999)) (newline)
(display "C(1000,1000) = ") (display (combinations 1000 1000)) (newline)
(display "C(15000,14998) = ") (display (combinations 15000 14998)) (newline)


EnableExplicit

Procedure.s CommaQuibble(Input$)
  Protected i, count
  Protected result$, word$
  Input$ = RemoveString(Input$, "[")
  Input$ = RemoveString(Input$, "]")
  Input$ = RemoveString(Input$, #DQUOTE$)
  count = CountString(Input$, ",") + 1
  result$ = "{"
  For i = 1 To count
    word$ = StringField(Input$, i, ",")
    If i = 1
      result$ + word$
    ElseIf Count = i
      result$ + " and " + word$
    Else
      result$ + ", " + word$
    EndIf
  Next
  ProcedureReturn result$ + "}"
EndProcedure

If OpenConsole()
  ; As 3 of the strings contain embedded quotes these need to be escaped with '\' and the whole string preceded by '~'
  PrintN(CommaQuibble("[]"))
  PrintN(CommaQuibble(~"[\"ABC\"]"))
  PrintN(CommaQuibble(~"[\"ABC\",\"DEF\"]"))
  PrintN(CommaQuibble(~"[\"ABC\",\"DEF\",\"G\",\"H\"]"))
  PrintN("")
  PrintN("Press any key to close the console")
  Repeat: Delay(10) : Until Inkey() <> ""
  CloseConsole()
EndIf


func P(n, k) { n! / ((n-k)!) }
func C(n, k) { binomial(n, k) }

class Logarithm(value) {
    method to_s {
        var e = int(value/10.log)
        "%.8fE%+d" % (exp(value - e*10.log), e)
    }
}

func lstirling(n) {
    n < 10 ? (lstirling(n+1) - log(n+1))
           : (0.5*log(2*Num.pi*n) + n*log(n/Num.e + 1/(12*Num.e*n)))
}

func P_approx(n, k) {
    Logarithm((lstirling(n) - lstirling(n -k)))
}

func C_approx(n, k) {
    Logarithm((lstirling(n) - lstirling(n -k) - lstirling(k)))
}

say "=> Exact results:"
for n (1..12) {
    var p = n//3
    say "P(#{n}, #{p}) = #{P(n, p)}"
}

for n (10..60 `by` 10) {
    var p = n//3
    say "C(#{n}, #{p}) = #{C(n, p)}"
}

say '';
say "=> Floating point approximations:"
for n ([5, 50, 500, 1000, 5000, 15000]) {
    var p = n//3
    say "P(#{n}, #{p}) = #{P_approx(n, p)}"
}

for n (100..1000 `by` 100) {
    var p = n//3
    say "C(#{n}, #{p}) = #{C_approx(n, p)}"
}


real scalar comb1(n, k) {
	return(exp(lnfactorial(n)-lnfactorial(k)-lnfactorial(n-k)))
}

real scalar perm(n, k) {
	return(exp(lnfactorial(n)-lnfactorial(n-k)))
}


>>> def strcat(sequence):
    return '{%s}' % ', '.join(sequence)[::-1].replace(',', 'dna ', 1)[::-1]

>>> for seq in ([], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]):
    print('Input: %-24r -> Output: %r' % (seq, strcat(seq)))

Input: []                       -> Output: '{}'
Input: ['ABC']                  -> Output: '{ABC}'
Input: ['ABC', 'DEF']           -> Output: '{ABC and DEF}'
Input: ['ABC', 'DEF', 'G', 'H'] -> Output: '{ABC, DEF, G and H}'
>>>


[ swap join join ]                    is glue     ( [ [ [ --> [ )

[ [ dup size
    dup 0 = iff
      [ 2drop [] ] done
    dup 1 = iff
      [ drop unpack ] done
    2 = iff
      [ unpack $ ' and ' glue ] done
    behead swap recurse $ ', ' glue ]
  $ '{' swap join $ '}' join ]         is quibble ( [     --> $ )

[] quibble echo$ cr
$ 'ABC' nest$ quibble echo$ cr
$ 'ABC DEF' nest$ quibble echo$ cr
$ 'ABC DEF G H' nest$ quibble echo$


import BigInt

func permutations(n: Int, k: Int) -> BigInt {
  let l = n - k + 1

  guard l <= n else {
    return 1
  }

  return (l...n).reduce(BigInt(1), { $0 * BigInt($1) })
}

func combinations(n: Int, k: Int) -> BigInt {
  let fact = {() -> BigInt in
    guard k > 1 else {
      return 1
    }

    return (2...k).map({ BigInt($0) }).reduce(1, *)
  }()

  return permutations(n: n, k: k) / fact
}

print("Sample of permutations from 1 to 12")

for i in 1...12 {
  print("\(i) P \(i / 3) = \(permutations(n: i, k: i / 3))")
}

print("\nSample of combinations from 10 to 60")

for i in stride(from: 10, through: 60, by: 10) {
  print("\(i) C \(i / 3) = \(combinations(n: i, k: i / 3))")
}

print("\nSample of permutations from 5 to 15,000")

for i in [5, 50, 500, 1000, 5000, 15000] {
  let k = i / 3
  let res = permutations(n: i, k: k).description
  let extra = res.count > 40 ? "... (\(res.count - 40) more digits)" : ""

  print("\(i) P \(k) = \(res.prefix(40))\(extra)")
}

print("\nSample of combinations from 100 to 1000")

for i in stride(from: 100, through: 1000, by: 100) {
  let k = i / 3
  let res = combinations(n: i, k: k).description
  let extra = res.count > 40 ? "... (\(res.count - 40) more digits)" : ""

  print("\(i) C \(k) = \(res.prefix(40))\(extra)")
}


# Exact integer versions
proc tcl::mathfunc::P {n k} {
    set t 1
    for {set i $n} {$i > $n-$k} {incr i -1} {
	set t [expr {$t * $i}]
    }
    return $t
}
proc tcl::mathfunc::C {n k} {
    set t [P $n $k]
    for {set i $k} {$i > 1} {incr i -1} {
	set t [expr {$t / $i}]
    }
    return $t
}

# Floating point versions using the Gamma function
package require math
proc tcl::mathfunc::lnGamma n {math::ln_Gamma $n}
proc tcl::mathfunc::fP {n k} {
    expr {exp(lnGamma($n+1) - lnGamma($n-$k+1))}
}
proc tcl::mathfunc::fC {n k} {
    expr {exp(lnGamma($n+1) - lnGamma($n-$k+1) - lnGamma($k+1))}
}


' Combinations and permutations - vbs - 10/04/2017
dim i,j
Wscript.StdOut.WriteLine  "-- Long Integer - Permutations - from 1 to 12"
for i=1 to 12
	for j=1 to i
		Wscript.StdOut.Write "P(" & i & "," & j & ")=" & perm(i,j) & "  "
	next 'j
	Wscript.StdOut.WriteLine ""
next 'i
Wscript.StdOut.WriteLine  "-- Float integer - Combinations from 10 to 60"
for i=10 to 60 step 10
	for j=1 to i step i\5
		Wscript.StdOut.Write  "C(" & i & "," & j & ")=" & comb(i,j) & "  "
	next 'j
	Wscript.StdOut.WriteLine ""
next 'i
Wscript.StdOut.WriteLine  "-- Float integer - Permutations from 5000 to 15000"
for i=5000 to 15000 step 5000
	for j=10 to 70 step 20
		Wscript.StdOut.Write  "C(" & i & "," & j & ")=" & perm(i,j) & "  "
	next 'j
	Wscript.StdOut.WriteLine ""
next 'i
Wscript.StdOut.WriteLine  "-- Float integer - Combinations from 200 to 1000"
for i=200 to 1000 step 200
	for j=20 to 100 step 20
		Wscript.StdOut.Write "P(" & i & "," & j & ")=" & comb(i,j) & "  "
	next 'j
	Wscript.StdOut.WriteLine ""
next 'i

function perm(x,y)
	dim i,z
	z=1
	for i=x-y+1 to x
		z=z*i
	next 'i
	perm=z
end function 'perm

function fact(x)
	dim i,z
	z=1
	for i=2 to x
		z=z*i
	next 'i
	fact=z
end function 'fact

function comb(byval x,byval y)
	if y>x then
		comb=0
	elseif x=y then
		comb=1
	else
		if x-y<y then y=x-y
		comb=perm(x,y)/fact(y)
	end if
end function 'comb


quib <- function(vect)
{
  #The task does not consider empty strings to be words, so we remove them immediately.
  #We could also remove non-upper-case characters, but the tasks gives off the impression that the user will do that.
  vect <- vect[nchar(vect) != 0]
  len <- length(vect)
  allButLastWord <- if(len >= 2) paste0(vect[seq_len(len - 1)], collapse = ", ") else ""
  paste0("{", if(nchar(allButLastWord) == 0) vect else paste0(allButLastWord, " and ", vect[len]), "}")
}
quib(character(0)) #R has several types of empty string, e.g. character(0), "", and c("", "", "").
quib("")
quib(" ")
quib(c("", ""))
quib(rep("", 10))
quib("ABC")
quib(c("ABC", ""))
quib(c("ABC", "DEF"))
quib(c("ABC", "DEF", "G", "H"))
quib(c("ABC", "DEF", "G", "H", "I", "J", ""))


(define (quibbling words)
  (define (sub-quibbling words)
    (match words
      ['() ""]
      [(list a) a]
      [(list a b) (format "~a and ~a" a b)]
      [(list a b ___) (format "~a, ~a" a (sub-quibbling b))]))
  (format "{~a}" (sub-quibbling words)))

(for ((input '([] ["ABC"] ["ABC" "DEF"] ["ABC" "DEF" "G" "H"])))
  (printf "~s\t->\t~a~%" input (quibbling input)))


' Combinations and permutations - 10/04/2017
Imports System.Numerics 'BigInteger
Module CombPermRc

    Sub Main()
        Dim i, j As Long
        For i = 1 To 12
            For j = 1 To i
                Console.Write("P(" & i & "," & j & ")=" & PermBig(i, j).ToString & "  ")
            Next j
            Console.WriteLine("")
        Next i
        Console.WriteLine("--")
        For i = 10 To 60 Step 10
            For j = 1 To i Step i \ 5
                Console.Write("C(" & i & "," & j & ")=" & CombBig(i, j).ToString & "  ")
            Next j
            Console.WriteLine("")
        Next i
        Console.WriteLine("--")
        For i = 5000 To 15000 Step 5000
            For j = 4000 To 5000 Step 1000
                Console.Write("P(" & i & "," & j & ")=" & PermBig(i, j).ToString("E") & "  ")
            Next j
            Console.WriteLine("")
        Next i
        Console.WriteLine("--")
        For i = 5000 To 15000 Step 5000
            For j = 4000 To 5000 Step 1000
                Console.Write("C(" & i & "," & j & ")=" & CombBig(i, j).ToString("E") & "  ")

            Next j
            Console.WriteLine("")
        Next i
        Console.WriteLine("--")
        i = 5000 : j = 4000
        Console.WriteLine("C(" & i & "," & j & ")=" & CombBig(i, j).ToString)
    End Sub 'Main

    Function PermBig(x As Long, y As Long) As BigInteger
        Dim i As Long, z As BigInteger
        z = 1
        For i = x - y + 1 To x
            z = z * i
        Next i
        Return (z)
    End Function 'PermBig

    Function FactBig(x As Long) As BigInteger
        Dim i As Long, z As BigInteger
        z = 1
        For i = 2 To x
            z = z * i
        Next i
        Return (z)
    End Function 'FactBig

    Function CombBig(ByVal x As Long, ByVal y As Long) As BigInteger
        If y > x Then
            Return (0)
        ElseIf x = y Then
            Return (1)
        Else
            If x - y < y Then y = x - y
            Return (PermBig(x, y) / FactBig(y))
        End If
    End Function 'CombBig

End Module


sub comma-quibbling(@A) {
    <{ }>.join: @A < 2 ?? @A !! "@A[0..*-2].join(', ') and @A[*-1]";
}

say comma-quibbling($_) for
    [], [<ABC>], [<ABC DEF>], [<ABC DEF G H>];


rebol []

comma-quibbling: func [block] [
    rejoin [
        "^{"

        to-string use [s] [
            s: copy block
            s: next s
            forskip s 2 [insert s either tail? next s [" and "] [", "]]
            s: head s
        ]

        "^}"
    ]
]

foreach t [[] [ABC] [ABC DEF] [ABC DEF G H]] [print comma-quibbling t]


import "/big" for BigInt
import "/fmt" for Fmt
import "/trait" for Stepped

var perm = Fn.new { |n, k|
    if (n <= 0 || k < 0) Fiber.abort("Invalid argument(s).")
    if (k == 0) return BigInt.one
    return (n-k+1..n).reduce(BigInt.one) { |acc, i| acc * BigInt.new(i) }
}

var comb = Fn.new { |n, k|
    if (n <= 0 || k < 0) Fiber.abort("Invalid argument(s).")
    var fact = BigInt.one
    if (k > 1) fact = (2..k).reduce(BigInt.one) { |acc, i| acc * BigInt.new(i) }
    return perm.call(n, k) / fact
}

System.print("A sample of permutations from 1 to 12:")
for (n in 1..12) Fmt.print("$2d P $-2d = $i", n, (n/3).floor, perm.call(n, (n/3).floor))

System.print("\nA sample of combinations from 10 to 60:")
for (n in Stepped.new(10..60, 10)) {
    Fmt.print("$2d C $-2d = $i", n, (n/3).floor, comb.call(n, (n/3).floor))
}

System.print("\nA sample of permutations from 5 to 15000:")
var na = [5, 50, 500, 1000, 5000, 15000]
for (n in na) {
    var k = (n/3).floor
    var s = perm.call(n, k).toString
    var l = s.count
    var e = (l <= 40) ? "" : "... (%(l - 40) more digits)"
    Fmt.print("$5d P $-4d = $s$s", n, k, s.take(40).join(), e)
}

System.print("\nA sample of combinations from 100 to 1000:")
for (n in Stepped.new(100..1000, 100)) {
    var k = (n/3).floor
    var s = comb.call(n, k).toString
    var l = s.count
    var e = (l <= 40) ? "" : "... (%(l - 40) more digits)"
    Fmt.print("$4d C $-3d = $s$s", n, k, s.take(40).join(), e)
}


say quibbling('')
say quibbling('ABC')
say quibbling('ABC DEF')
say quibbling('ABC DEF G H')
exit

quibbling: procedure
    parse arg list
    Select
      When list='' Then result=''
      When words(list)=1 then result=word(list,1)
      Otherwise result=translate(strip(subword(list,1,words(list)-1)),',',' '),
        'and' word(list,words(list))
      End
    Return '{'result'}'


# Project : Comma Quibbling

text = list(4)
text[1] = "{}"
text[2] = "ABC"
text[3] = "ABC,DEF"
text[4] = "ABC,DEF,G,H"
comma(text)

func comma(text)
       listtext = []
       for n = 1 to 4
            listtext = str2list(substr(text[n], ",", nl))
            if n = 2
               see "{" + list2str(listtext) + "}" + nl
               loop
            ok
            if len(listtext) = 1
               see "{}" + nl
               loop
            ok
            str = "{"
            for m = 1 to len(listtext)-1
                if len(listtext) = 2
                   str = str + listtext[m] + " "
                else
                   str = str + listtext[m] + ", "
                ok
            next
            if len(listtext) = 2
               str = left(str, len(str)-1)
            else
               str = left(str, len(str)-2)
            ok
            if len(listtext) = 2
               str = str + " " + listtext[len(listtext)] + "}"
            else
               str = str + " and " + listtext[len(listtext)] + "}"
            ok
            see str + nl
     next


def comma_quibbling(a)
  %w<{ }>.join(a.length < 2 ? a.first :
               "#{a[0..-2].join(', ')} and #{a[-1]}")
end

[[], %w<ABC>, %w<ABC DEF>, %w<ABC DEF G H>].each do |a|
  puts comma_quibbling(a)
end


def quibble( s:List[String] ) = s match {
  case m if m.isEmpty => "{}"
  case m if m.length < 3 => m.mkString("{", " and ", "}")
  case m => "{" + m.init.mkString(", ") + " and " + m.last + "}"
}

// A little test...
{
  println( quibble( List() ) )
  println( quibble( List("ABC") ) )
  println( quibble( List("ABC","DEF") ) )
  println( quibble( List("ABC","DEF","G","H") ) )
}


(define (quibble . args)
  (display "{")
  (do ((rem args (cdr rem)))
    ((null? rem) (display "}\n"))
    (display (car rem))
    (cond ((= 1 (length rem)) )
          ((= 2 (length rem))
           (display " and "))
          (else
            (display ", ")))))

(quibble)
(quibble "ABC")
(quibble "ABC" "DEF")
(quibble "ABC" "DEF" "G" "H")


$ include "seed7_05.s7i";

const func string: quibble (in array string: input) is func
  result
    var string: quibble is "{";
  begin
    case length(input) of
      when {0}:  quibble &:= "}";
      when {1}:  quibble &:= input[1] & "}";
      otherwise: quibble &:= join(input[.. pred(length(input))], ", ") &
                             " and " & input[length(input)] & "}";
    end case;
  end func;

const proc: main is func
  begin
    writeln(quibble(0 times ""));
    writeln(quibble([] ("ABC")));
    writeln(quibble([] ("ABC", "DEF")));
    writeln(quibble([] ("ABC", "DEF", "G", "H")));
  end func;


Quibble [] // (No input words).
Quibble ["ABC"]
Quibble ["ABC", "DEF"]
Quibble ["ABC", "DEF", "G", "H"]

to Quibble with wordList
	if the number of items in wordList is ...
		... 0 then put "{}"
		... 1 then put "{" & item 1 of wordList & "}"
		... else put "{" & (items first to penultimate of wordList) joined by ", " & " and " & the last item of wordlist & "}"
	end if
end Quibble


func comma_quibbling(words) {
    '{' + ([words.ft(0, -2).join(', ')]-[''] + [words.last] -> join(' and ')) + '}';
}

[<>, <ABC>, <ABC DEF>, <ABC DEF G H>].each { |w|
    say comma_quibbling(w);
}


local
  fun quib []      = ""
    | quib [x]     = x
    | quib [x0,x1] = x0 ^ " and " ^ x1
    | quib (x::xs) = x ^ ", " ^ quib xs
in
  fun quibble xs = "{" ^ quib xs ^ "}"
end

(* Tests: *)
val t_quibble_0 = quibble [] = "{}"
val t_quibble_1 = quibble ["ABC"] = "{ABC}"
val t_quibble_2 = quibble ["ABC", "DEF"] = "{ABC and DEF}"
val t_quibble_3 = quibble ["ABC", "DEF", "G", "H"] = "{ABC, DEF, G and H}"


let inputs = [[], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]]

func quibbling(var words:[String]) {
    if words.count == 0 {
        println("{}")
    } else if words.count == 1 {
        println("{\(words[0])}")
    } else if words.count == 2 {
        println("{\(words[0]) and \(words[1])}")
    } else {
        var output = "{"
        while words.count != 2 {
            output += words.removeAtIndex(0) + ", "
        }
        output += "\(words.removeAtIndex(0)) and \(words.removeAtIndex(0))}"

        println(output)
    }
}

for word in inputs {
    quibbling(word)
}


proc commaQuibble {lst} {
    return \{[join [lreplace $lst end-1 end [join [lrange $lst end-1 end] " and "]] ", "]\}
}

foreach input { {} {"ABC"} {"ABC" "DEF"} {"ABC" "DEF" "G" "H"} } {
    puts [commaQuibble $input]
}


(defun quib (list)
  (tree-bind (: last . lead) (reverse list)
    `{@{(nreverse lead) ", "}@(if lead " and ")@last}`))


quibble() {
	# Here awk(1) is easier than sed(1).
	awk 'BEGIN {
		for (i = 1; i < ARGC - 2; i++) s = s ARGV[i] ", "
		i = ARGC - 2; if (i > 0) s = s ARGV[i] " and "
		i = ARGC - 1; if (i > 0) s = s ARGV[i]
		printf "{%s}\n", s
		exit 0
	}' "[email protected]"
}

quibble
quibble ABC
quibble ABC DEF
quibble ABC DEF G H


Option Explicit

Sub Main()
   Debug.Print Quibbling("")
   Debug.Print Quibbling("ABC")
   Debug.Print Quibbling("ABC, DEF")
   Debug.Print Quibbling("ABC, DEF, G, H")
   Debug.Print Quibbling("ABC, DEF, G, H, IJKLM, NO, PQRSTUV")
End Sub

Private Function Quibbling(MyString As String) As String
Dim s As String, n As Integer
   s = "{" & MyString & "}": n = InStrRev(s, ",")
   If n > 0 Then s = Left(s, n - 1) & " and " & Right(s, Len(s) - (n + 1))
   Quibbling = s
End Function


Function Quibble(s)
	arr = Split(s,",")
	If s = "" Then
		Quibble = "{}"
	ElseIf UBound(arr) = 0 Then
		Quibble = "{" & arr(0) & "}"
	Else
		Quibble = "{"
		For i = 0 To UBound(arr)
			If i = UBound(arr) - 1 Then
				Quibble = Quibble & arr(i) & " and " & arr(i + 1) & "}"
				Exit For
			Else
				Quibble = Quibble & arr(i) & ", "
			End If
		Next
	End If
End Function

WScript.StdOut.Write Quibble("")
WScript.StdOut.WriteLine
WScript.StdOut.Write Quibble("ABC")
WScript.StdOut.WriteLine
WScript.StdOut.Write Quibble("ABC,DEF")
WScript.StdOut.WriteLine
WScript.StdOut.Write Quibble("ABC,DEF,G,H")
WScript.StdOut.WriteLine


Option Explicit On
Option Infer On
Option Strict On

Module Program
    Function FormatEnumerable(source As IEnumerable(Of String)) As String
        Dim res As New Text.StringBuilder("{")

        Using en = source.GetEnumerator()
            Dim moreThanOne As Boolean = False
            Dim nxt = If(en.MoveNext(), en.Current, String.Empty)

            Do While en.MoveNext()
                If moreThanOne Then res.Append(", ")
                moreThanOne = True

                res.Append(nxt)
                nxt = en.Current
            Loop

            Dim lastItem = If(moreThanOne, " and ", "") & nxt
            Return res.ToString() & lastItem & "}"
        End Using
    End Function

    Function FormatArray(source As String()) As String
        Select Case source.Length
            Case 0 : Return "{}"
            Case 1 : Return "{" & source(0) & "}"
            Case Else : Return "{" & String.Join(", ", source.Take(source.Length - 1)) & " and " & source(source.Length - 1) & "}"
        End Select
    End Function

    Sub Main()
        Dim cases As String()() = {Array.Empty(Of String), New String() {"ABC"}, New String() {"ABC", "DEF"}, New String() {"ABC", "DEF", "G", "H"}}
        For Each c In cases
            Console.WriteLine(FormatArray(c))
            Console.WriteLine(FormatEnumerable(c))
        Next
    End Sub
End Module


#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>

bool colorful(int n) {
    // A colorful number cannot be greater than 98765432.
    if (n < 0 || n > 98765432)
        return false;
    int digit_count[10] = {};
    int digits[8] = {};
    int num_digits = 0;
    for (int m = n; m > 0; m /= 10) {
        int d = m % 10;
        if (n > 9 && (d == 0 || d == 1))
            return false;
        if (++digit_count[d] > 1)
            return false;
        digits[num_digits++] = d;
    }
    // Maximum number of products is (8 x 9) / 2.
    int products[36] = {};
    for (int i = 0, product_count = 0; i < num_digits; ++i) {
        for (int j = i, p = 1; j < num_digits; ++j) {
            p *= digits[j];
            for (int k = 0; k < product_count; ++k) {
                if (products[k] == p)
                    return false;
            }
            products[product_count++] = p;
        }
    }
    return true;
}

static int count[8];
static bool used[10];
static int largest = 0;

void count_colorful(int taken, int n, int digits) {
    if (taken == 0) {
        for (int d = 0; d < 10; ++d) {
            used[d] = true;
            count_colorful(d < 2 ? 9 : 1, d, 1);
            used[d] = false;
        }
    } else {
        if (colorful(n)) {
            ++count[digits - 1];
            if (n > largest)
                largest = n;
        }
        if (taken < 9) {
            for (int d = 2; d < 10; ++d) {
                if (!used[d]) {
                    used[d] = true;
                    count_colorful(taken + 1, n * 10 + d, digits + 1);
                    used[d] = false;
                }
            }
        }
    }
}

int main() {
    setlocale(LC_ALL, "");

    clock_t start = clock();

    printf("Colorful numbers less than 100:\n");
    for (int n = 0, count = 0; n < 100; ++n) {
        if (colorful(n))
            printf("%2d%c", n, ++count % 10 == 0 ? '\n' : ' ');
    }

    count_colorful(0, 0, 0);
    printf("\n\nLargest colorful number: %'d\n", largest);

    printf("\nCount of colorful numbers by number of digits:\n");
    int total = 0;
    for (int d = 0; d < 8; ++d) {
        printf("%d   %'d\n", d + 1, count[d]);
        total += count[d];
    }
    printf("\nTotal: %'d\n", total);

    clock_t end = clock();
    printf("\nElapsed time: %f seconds\n",
           (end - start + 0.0) / CLOCKS_PER_SEC);
    return 0;
}


fn q(s []string) string {
    match s.len {
        0 {
            return '{}'
        }
        1 {
            return '{${s[0]}}'
        }
        2 {
            return '{${s[0]} and ${s[1]}}'
        }
        else{
            return '{${s[0..s.len-1].join(', ')} and ${s[s.len-1]}}'
        }
    }
}

fn main(){
    println(q([]))
    println(q(['ABC']))
    println(q(['ABC','DEF']))
    println(q(['ABC','DEF','G','H']))
}


var quibbling = Fn.new { |w|
    var c = w.count
    if (c == 0) return "{}"
    if (c == 1) return "{%(w[0])}"
    if (c == 2) return "{%(w[0]) and %(w[1])}"
    return "{%(w[0..-2].join(", ")) and %(w[-1])}"
}

var words = [ [], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"] ]
for (w in words) System.print(quibbling.call(w))


USING: assocs grouping grouping.extras io kernel literals math
math.combinatorics math.ranges prettyprint project-euler.common
sequences sequences.extras sets ;

CONSTANT: digits $[ 2 9 [a..b] ]

: (colorful?) ( seq -- ? )
    all-subseqs [ product ] map all-unique? ;

: colorful? ( n -- ? )
    [ t ] [ number>digits (colorful?) ] if-zero ;

: table. ( seq cols -- )
    [ "" pad-groups ] keep group simple-table. ;

: (oom-count) ( n -- count )
    digits swap <k-permutations> [ (colorful?) ] count ;

: oom-count ( n -- count )
    dup 1 = [ drop 10 ] [ (oom-count) ] if ;

"Colorful numbers under 100:" print
100 <iota> [ colorful? ] filter 10 table. nl

"Largest colorful number:" print
digits <permutations> [ (colorful?) ] find-last nip digits>number . nl

"Count of colorful numbers by number of digits:" print
8 [1..b] [ oom-count ] zip-with dup .
"Total: " write values sum .


package main

import (
    "fmt"
    "rcu"
    "strconv"
)

func isColorful(n int) bool {
    if n < 0 {
        return false
    }
    if n < 10 {
        return true
    }
    digits := rcu.Digits(n, 10)
    for _, d := range digits {
        if d == 0 || d == 1 {
            return false
        }
    }
    set := make(map[int]bool)
    for _, d := range digits {
        set[d] = true
    }
    dc := len(digits)
    if len(set) < dc {
        return false
    }
    for k := 2; k <= dc; k++ {
        for i := 0; i <= dc-k; i++ {
            prod := 1
            for j := i; j <= i+k-1; j++ {
                prod *= digits[j]
            }
            if ok := set[prod]; ok {
                return false
            }
            set[prod] = true
        }
    }
    return true
}

var count = make([]int, 9)
var used = make([]bool, 11)
var largest = 0

func countColorful(taken int, n string) {
    if taken == 0 {
        for digit := 0; digit < 10; digit++ {
            dx := digit + 1
            used[dx] = true
            t := 1
            if digit < 2 {
                t = 9
            }
            countColorful(t, string(digit+48))
            used[dx] = false
        }
    } else {
        nn, _ := strconv.Atoi(n)
        if isColorful(nn) {
            ln := len(n)
            count[ln]++
            if nn > largest {
                largest = nn
            }
        }
        if taken < 9 {
            for digit := 2; digit < 10; digit++ {
                dx := digit + 1
                if !used[dx] {
                    used[dx] = true
                    countColorful(taken+1, n+string(digit+48))
                    used[dx] = false
                }
            }
        }
    }
}

func main() {
    var cn []int
    for i := 0; i < 100; i++ {
        if isColorful(i) {
            cn = append(cn, i)
        }
    }
    fmt.Println("The", len(cn), "colorful numbers less than 100 are:")
    for i := 0; i < len(cn); i++ {
        fmt.Printf("%2d ", cn[i])
        if (i+1)%10 == 0 {
            fmt.Println()
        }
    }

    countColorful(0, "")
    fmt.Println("\n\nThe largest possible colorful number is:")
    fmt.Println(rcu.Commatize(largest))

    fmt.Println("\nCount of colorful numbers for each order of magnitude:")
    pow := 10
    for dc := 1; dc < len(count); dc++ {
        cdc := rcu.Commatize(count[dc])
        pc := 100 * float64(count[dc]) / float64(pow)
        fmt.Printf("  %d digit colorful number count: %6s - %7.3f%%\n", dc, cdc, pc)
        if pow == 10 {
            pow = 90
        } else {
            pow *= 10
        }
    }

    sum := 0
    for _, c := range count {
        sum += c
    }
    fmt.Printf("\nTotal colorful numbers: %s\n", rcu.Commatize(sum))
}


func task(a:array){
	set x:string="";
	foreach(k,v as a){
		set out:string="";
		if ((k==(?a-2))&((?a)>1)){out=" and "}elif(k!=(?a-1)){out=", "}
		x+=v+out;del out;
	}
	send "{"+x+"}";
}

log(task([]));
log(task(["ABC"]));
log(task(["ABC","DEF"]));
log(task(["ABC","DEF","GHI"]));


(defun quibble (inputs &optional oxford-comma)
    (define final
        (if (and (caddr inputs) oxford-comma)
            ", and "
            " and " ) )
    (defun comma-quibble (words)
        (cond
            ((null words) "")
            ((null (cdr words)) (car words))
            (t (begin
                (string-append (car words)
                    (if (caddr words)
                        (string-append ", " (comma-quibble (cdr words)))
                        (string-append final (cadr words))) ) ) ) ) )
    (string-append "{" (comma-quibble inputs) "}") )

; test cases:
(print (quibble '())) ; empty list
(print (quibble '("ABC")))
(print (quibble '("ABC" "DEF")))
(print (quibble '("ABC" "DEF" "G" "H")))

(newline)

; test cases using the Oxford comma:
(print (quibble '() t))
(print (quibble '("ABC") t))
(print (quibble '("ABC" "DEF") t))
(print (quibble '("ABC" "DEF" "G" "H") t))


import Data.List ( nub )
import Data.List.Split ( divvy )
import Data.Char ( digitToInt )

isColourful :: Integer -> Bool
isColourful n
   |n >= 0 && n <= 10 = True
   |n > 10 && n < 100 = ((length s) == (length $ nub s)) &&
    (not $ any (\c -> elem c "01") s)
   |n >= 100 = ((length s) == (length $ nub s)) && (not $ any (\c -> elem c "01") s)
     && ((length products) == (length $ nub products))
    where
     s :: String
     s = show n
     products :: [Int]
     products = map (\p -> (digitToInt $ head p) * (digitToInt $ last p))
      $ divvy 2 1 s

solution1 :: [Integer]
solution1 = filter isColourful [0 .. 100]

solution2 :: Integer
solution2 = head $ filter isColourful [98765432, 98765431 ..]


include c:\cxpl\codes;

proc Quibble(N, S);
int  N, S;
int  I;
[ChOut(0, ^{);
for I:= 0 to N-1 do
    [Text(0, S(I));
    if I<N-2 then Text(0, ", ");
    if I=N-2 then Text(0, " and ");
    ];
ChOut(0, ^});
];

int I;
for I:= 0 to 4 do
    if I#3 then [Quibble(I, ["ABC", "DEF", "G", "H"]);  CrLf(0)]


fcn quib(list){ text:=("{"+list.toString(*)[2,-1]+"}").replace("\"","");
   if(list.len()<2) text;
   else{
      z:=(text=text.replace(",",", ")).rfind(",");
      String(text[0,z]," and ",text[z+2,*])
   }
}


10 DATA 0
20 DATA 1,"ABC"
30 DATA 2,"ABC","DEF"
40 DATA 4,"ABC","DEF","G","H"
50 FOR n=10 TO 40 STEP 10
60 RESTORE n: GO SUB 1000
70 NEXT n
80 STOP
1000 REM quibble
1010 LET s$=""
1020 READ j
1030 IF j=0 THEN GO TO 1100
1040 FOR i=1 TO j
1050 READ a$
1060 LET s$=s$+a$
1070 IF (i+1)=j THEN LET s$=s$+" and ": GO TO 1090
1080 IF (i+1)<j THEN LET s$=s$+", "
1090 NEXT i
1100 PRINT "{";s$;"}"
1110 RETURN


public class ColorfulNumbers {
    private int count[] = new int[8];
    private boolean used[] = new boolean[10];
    private int largest = 0;

    public static void main(String[] args) {
        System.out.printf("Colorful numbers less than 100:\n");
        for (int n = 0, count = 0; n < 100; ++n) {
            if (isColorful(n))
                System.out.printf("%2d%c", n, ++count % 10 == 0 ? '\n' : ' ');
        }

        ColorfulNumbers c = new ColorfulNumbers();

        System.out.printf("\n\nLargest colorful number: %,d\n", c.largest);

        System.out.printf("\nCount of colorful numbers by number of digits:\n");
        int total = 0;
        for (int d = 0; d < 8; ++d) {
            System.out.printf("%d   %,d\n", d + 1, c.count[d]);
            total += c.count[d];
        }
        System.out.printf("\nTotal: %,d\n", total);
    }

    private ColorfulNumbers() {
        countColorful(0, 0, 0);
    }

    public static boolean isColorful(int n) {
        // A colorful number cannot be greater than 98765432.
        if (n < 0 || n > 98765432)
            return false;
        int digit_count[] = new int[10];
        int digits[] = new int[8];
        int num_digits = 0;
        for (int m = n; m > 0; m /= 10) {
            int d = m % 10;
            if (n > 9 && (d == 0 || d == 1))
                return false;
            if (++digit_count[d] > 1)
                return false;
            digits[num_digits++] = d;
        }
        // Maximum number of products is (8 x 9) / 2.
        int products[] = new int[36];
        for (int i = 0, product_count = 0; i < num_digits; ++i) {
            for (int j = i, p = 1; j < num_digits; ++j) {
                p *= digits[j];
                for (int k = 0; k < product_count; ++k) {
                    if (products[k] == p)
                        return false;
                }
                products[product_count++] = p;
            }
        }
        return true;
    }

    private void countColorful(int taken, int n, int digits) {
        if (taken == 0) {
            for (int d = 0; d < 10; ++d) {
                used[d] = true;
                countColorful(d < 2 ? 9 : 1, d, 1);
                used[d] = false;
            }
        } else {
            if (isColorful(n)) {
                ++count[digits - 1];
                if (n > largest)
                    largest = n;
            }
            if (taken < 9) {
                for (int d = 2; d < 10; ++d) {
                    if (!used[d]) {
                        used[d] = true;
                        countColorful(taken + 1, n * 10 + d, digits + 1);
                        used[d] = false;
                    }
                }
            }
        }
    }
}