2009-06-26 11 views
1

アイデアはそうfun foo y x又はfun foo z y xような機能は全体正方形X Y又はキューブX Yに適用することができる範囲として定義各純粋な機能的なMLでN次元の散歩をしていますか?

(* lower_bound, upper_bound, number_of_steps *) 
type range = real * real * int 

、複数の次元にわたって歩くことです* Z.

test2.sml:7.5-22.6 Error: right-hand-side of clause doesn't agree with function result type [circularity] 
    expression: (real -> 'Z) -> unit 
    result type: 'Z -> 'Y 
    in declaration: 
    walk = (fn arg => (fn <pat> => <exp>)) 

ここでコードがあります:

SML/NJは、以下の私の実装が好きではありません

fun walk []  _ =() 
    | walk (r::rs) f = 
    let 
    val (k0, k1, n) = r 
    val delta = k1 - k0 
    val step = delta/real n 

    fun loop 0 _ =() 
     | loop i k = 
     let in 
      walk rs (f k) ;   (* Note (f k) "eats" the first argument. 
             I guess SML doesn't like having the 
             type of walk change in the middle of its 
             definition *) 
      loop (i - 1) (k + step) 
     end 
    in 
    loop n k0 
    end 

fun do2D y x = (* ... *)() 
fun do3D z y x = (* ... *)() 

val x_axis = (0.0, 1.0, 10) 
val y_axis = (0.0, 1.0, 10) 
val z_axis = (0.0, 1.0, 10) 

val _ = walk [y_axis, x_axis] do2D 
val _ = walk [z_axis, y_axis, x_axis] do3D 

さえ可能コンストラクトのこの種のですか?

任意のポインタを歓迎します。

+1

ところで、私はあなたの「純粋な機能」の使用に同意しません。これはSMLのような命令的言語でのみ有効です。 'ユニット。ユニットの配列決定は副作用なしに無意味である。 – ephemient

+0

それは私が期待したものですが、それはまったく純粋ではありません。まあ、少なくとも純粋に純粋な他の関数型言語とは異なり、SMLは保証された評価順序を持っています。 – ephemient

+0

真ですが、関数do2Dとdo3Dは単純なprint文ですので、テストのためにできるだけ多くのコードを削除しました – diapir

答えて

1

walkはMLのタイプのシステムで表現できますか?

val walk : range list -> (real -> real -> unit) -> unit 
val walk : range list -> (real -> real -> real -> unit) -> unit 

MLの両方のタイプで同じ値が存在する可能性はありません。


ただし、目的のタイプごとに値を簡単に生成できます。

type range = real * real * int 

signature WALK = 
    sig 
    type apply 
    val walk : range list -> apply -> unit 
    end 

structure Walk0 : WALK = 
    struct 
    type apply = unit 
    fun walk _ _ =() 
    end 

functor WALKF (Walk : WALK) : WALK = 
    struct 
    type apply = real -> Walk.apply 
    fun walk ((low, high, steps)::rs) f = 
      let fun loop i = 
       if i > steps then() else 
        let val x = low + (high - low) * real i/real steps 
        in (Walk.walk rs (f x); loop (i + 1)) end 
      in loop 0 end 
    end 

struture Walk1 = WALKF(Walk0) 
struture Walk2 = WALKF(Walk1) 
struture Walk3 = WALKF(Walk2) 

これにより、以下の値が目的のタイプに存在します。

val Walk0.walk : range list -> unit -> unit 
val Walk1.walk : range list -> (real -> unit) -> unit 
val Walk2.walk : range list -> (real -> real -> unit) -> unit 
val Walk3.walk : range list -> (real -> real -> real -> unit) -> unit 

その後、あなただけのすべての次元に同じwalkを使用するには

val _ = Walk2.walk [y_axis, x_axis] do2D 
val _ = Walk3.walk [z_axis, y_axis, x_axis] do3D 

を記述する必要がある、あなたはそれがすべての次元で同じタイプを使用する必要があります。

fun walk nil f = f nil 
    | walk ((low, high, steps)::rs) f = 
     let fun loop i = 
      if i > steps then() else 
       let val x = low + (high - low) * real i/real steps 
       in (walk rs (fn xs -> f (x::xs)); loop (i + 1)) end 
     in loop 0 end 

はタイプが

val walk : range list -> (real list -> unit) -> unit 

使用状況に変更されるためにも、このimplementation for variable number of argumentsを発見

fun do2D [y,x] = (* ... *)() 
fun do3D [z,y,x] = (* ... *)() 
+0

うわー、ありがとう。私はまだ推測していたファンクタの周りに頭を浮かべる必要があります...)あなたの最初の解決策は酷いハックかいくつかの正当なコードだと思いますか?また、私のスタイルの不一致を指摘してくれてありがとう。乾杯。 – diapir

+0

私は最初の解決策をハックとは考えていません。実際、最初の解は、 'f'が常に正しい数の引数を取ることを保証しますが、' f'は常に正しい数の引数を取ることを保証します。しかし、範囲のリストに正しい長さがあることを保証するものではないので、私は一般的にこの構造が気に入らない。 – ephemient

0

に変更することがあります。それは当てはまりませんが、それはかなり醜いように見えます。

+0

ああ、あの$ハックは信じられません...そうです、それはHaskellの "可変引数"の回避策とほぼ同じですが、型クセストと依存型の欠如のためにさらに多くの痛みがあります。 – ephemient

1
fun walk lst f = let 
    fun aux rev_prefix [] = f (rev rev_prefix) 
    | aux rev_prefix (r::rs) = let 
     val (k0, k1, n) = r 
     val delta = k1 - k0 
     val step = delta/real n 

     fun loop 0 _ =() 
      | loop i k = (
       aux (k+step :: rev_prefix) rs; 
       loop (i - 1) (k + step) 
      ) 
     in 
     loop n k0 
     end 
in 
    aux [] lst 
end 

fun do2D [x,y] = print (Real.toString x^"\t"^
         Real.toString y^"\n") 
fun do3D [x,y,z] = print (Real.toString x^"\t"^
          Real.toString y^"\t"^
          Real.toString z^"\n") 

val x_axis = (0.0, 1.0, 10) 
val y_axis = (0.0, 1.0, 10) 
val z_axis = (0.0, 1.0, 10) 

val() = walk [y_axis, x_axis] do2D 
val() = walk [z_axis, y_axis, x_axis] do3D 
+0

私の2番目の解決策に見えますか? ( 'fun walk2 l f = walk l(f o rev)'ラッパーで)。 – ephemient

関連する問題