4

Cleave は、コードの重複を最小限に抑えるための非常に便利なコンビネーターです。Abundant、Perfect、Deficient の数を分類したいとします。

USING: arrays assocs combinators formatting io kernel math
math.order math.primes.factors math.ranges sequences ;
IN: adp

CONSTANT: ADP { "deficient" "perfect" "abundant" }

: proper-divisors ( n -- seq )
  dup zero? [ drop { } ] [ divisors dup length 1 - head ] if ;

: adp-classify ( n -- a/d/p )
  dup proper-divisors sum <=>
  { +lt+ +eq+ +gt+ } ADP zip
  H{ } assoc-clone-like at ;

: range>adp-classes ( n -- seq )
  1 swap 1 <range> [ adp-classify ] map
  ADP dup
  [
    [
      [ = ]     curry
      [ count ] curry
    ] map
    cleave 3array
  ] dip
  swap zip H{ } assoc-clone-like ;

: print-adp-stats ( seq -- )
  ADP [
   [ dup [ swap at ] dip swap "%s: %s" sprintf ] curry
  ] map cleave
  [ print ] tri@ ;

range>adp-classes「実行時に計算された値にクリーブを適用できない」ため、コンパイルされません。

クリーブを使用できない場合は、基本的に次のことを行う必要があります。

[ [ [ "deficient" = ] count ] 
  [ [ "abundant" = ] count ]
  [ [ "perfect" = ] count ]
  tri
] dip

これは不自由で長く、キー文字列の配列がより長い場合、非常に醜く長くなります。また、キーの配列が実行時に生成される場合、切断せずに実行することは不可能です。

同様にprint-adp-stats: なしcleaveでは、このリテラルをソースに配置する必要があります。

{
    [ "deficient" dup [ swap at ] dip swap "%s: %s" sprintf ]
    [ "perfect" dup [ swap at ] dip swap "%s: %s" sprintf ]
    [ "abundant" dup [ swap at ] dip swap "%s: %s" sprintf ]
}

きもい。

cleave実行時の計算値を置き換えるコンビネータはありますか? 実行時に計算を許可しながら、他の方法で醜い重複を最小限に抑えることはできますか?

4

1 に答える 1