2017-10-25 7 views
1

シェイプレスを使用して、ドキュメントに記載されているレシピを使用してアライティを抽象化することができます。シェイプレスを使用したアライティの概要

しかし、私は例えば、この機能をラップすることができないよ
import shapeless.ops.function.FnToProduct 
import shapeless.{Generic, HList} 
import shapeless._ 
import syntax.std.function._ 

def applyProduct[P <: Product, F, L <: HList, R](p: P)(f: F)(implicit gen: Generic.Aux[P, L], fp: FnToProduct.Aux[F, L => R]) = 
    f.toProduct(gen.to(p)) 

val add = (x: Int, y: Int) => x + y 

applyProduct(1, 2)(add) 

def applyProduct[P <: Product, F, L <: HList, R](p: P)(f: F)(implicit gen: Generic.Aux[P, L], fp: FnToProduct.Aux[F, L => R]) = 
    f.toProduct(gen.to(p)) 

val add = (x: Int, y: Int) => x + y 

def wrapper[F](f: F) { 
    applyProduct(1, 2)(f) 
} 

wrapper(add) 

コンパイラは、それがKを回すことができないされていることを意味find implicit value for parameter fp: shapeless.ops.function.FnToProduct.Aux[(A, A) => A,L => R]

できないと主張-ary関数を、同じ引数型のKサイズのHListの関数に変換します。

どうすればいいですか?

編集:

オクラホマので、今私は、ある時点での機能を知っているが、私はちょうど後で引数を知っているだろうので、私は評価

case class Node[P <: Product, F, L <: HList, R](f: F)(implicit gen:Generic.Aux[P, L], fp: FnToProduct.Aux[F, L => R]) { 
    def evaluate(p: P) = { 
    f.toProduct(gen.to(p)) 
    } 
} 
に延期することを想像し

コンパイラは、私が呼び出すことはできません。

val add = (x: Int, y: Int) => x + y 

val n = Node(add) 

//later 

n.evaluate(1,2,3) 

は、私はこれを解決するために、部分的アプリケーションを使用することができませんか?

答えて

3

は、それはそれと同じくらい簡単です:あなたはすでにそれがFの上に抽象的にどんな意味がありませんので、あなたのラッパー内(1,2)を渡すことで((Int, Int)として)Pタイプを定義し

def wrapper[R](f: (Int, Int) => R) = { 
    applyProduct(1, 2)(f) 
} 

- 唯一の事あなたを抽象オーバーが R(結果タイプ)

説明:wrapper

applyProductありませんFについては何でも知っている。だから、FnToProduct.Aux[F, ...]スカラーコンパイラが何であるかについての詳細を知る必要があるので、FnToProduct.Auxが暗黙的に定義されている "形状"が(A, A) => A(あなたの場合は(Int, Int) => Int)であり、ちょうどFエラーメッセージからあなたに伝えます。編集に


応答:

@ applyProduct(_: Int, _: Int)(add) 
res17: (Int, Int) => Int = 

@ res17(1,2) 
res18: Int = 3 

、あなたは(良いスタイルとはみなされないだけでnewを回避するためのケースクラスを使用してNodeケースクラスのようなものを使用することができますタイプascriptionsを避けるために、 )、クラスを導入することなく(単に関数からλを返す)。しかし、Nodeの場合のように、Scalaはすべての型引数を渡さなければ適切な型推論を行うことができません。

残念ながら、ここでのカリング(f: Fを最初の引数にする)を使用すると便利ではありません。「implicits」はすべての型引数を渡さなければ解決しません。たぶん、それをハックする方法がありますが、部分的なアプリケーションは最もシンプルで理解しやすいようです。

P.S.それは、引数(減速)(またはリスト)2を取る機能を持っているより多くの意味になるだろうが、の関数に変換される

@ val ff = add _; val f = ff() 
ff:() => (Int, Int) => Int = 
f: (Int, Int) => Int = ammonite.$sess.cmd9$$$Lambda$1978/[email protected] 

@ f(1,2) 
res34: Int = 3 

:あなたはこのような場合のために、このような部分的なアプリケーションはと等価であることが気づくことができ任意のアリティ(def abstract[...](f: (A, A) => A)(p: P): Aなど)。それは、アリティよりも真の抽象化であろう。

+0

ご説明いただきありがとうございます。これで、なぜそれがコンパイルされなかったのかは明らかです。しかし、私はこれを本当に長い間滞在していたと信じています。しかし 'F'で抽象化することはできないのですか?私が '(1,2)を修正しているので意味がありません。しかし、一般的には、私は –

+1

@ cylindferreira "Fで抽象化することはできないのですか?"確かに、それはあなたが最初にやっていたことであり、それは働いていました:)真剣に言えば、ラッパーの中で 'F 'を抽象化することを意味するならば、' applyProduct'の場合と同じです:呼び出し側に再度 'implicits'を要求しなければなりません、別名' wrapper [F、...](f:F )(暗黙のgen、fp) ' - 場合によっては、より少ない型と暗黙のパラメータが必要になるかもしれません(あなたが事前にarityを知っているなら'gen'をrepropagateする必要はないかもしれません)。 – dk14

+0

はい、私は、元の宣言に戻る必要があります、ありがとう!それでも、私のユースケースは少し異なります。私は編集しました、多分私の目的をより明確に理解することができます。私は本当にscalaの初心者です。 –

関連する問題