6

Project Eulerを調べて F# を学ぼうとしているときに、問題 3の解決策を書いているときに、型推論の問題と思われるものに出くわしました。

ここに私が書いたものがあります:

let rec findLargestPrimeFactor p n = 
    if n = 1 then p
    else
        if n % p = 0 then findLargestPrimeFactor p (n/p)
        else findLargestPrimeFactor (p+1) n

let result = findLargestPrimeFactor 2 600851475143L

ただし、コンパイラは次のエラーを表示します。

エラー FS0001: この式は int 型であると予想されていましたが、ここでは int64 型です

で使用されている型は使用法から推測されると予想しているので、関数への唯一の呼び出しは int64 で行わfindLargestPrimeFactorれるため、コンパイラがパラメーターが int であると想定しているように見えることに非常に驚いています。n

誰かが私に説明できますか:

  1. コンパイラが型について混乱しているように見える理由
  2. この制限を回避する方法
4

1 に答える 1

11

の型はfindLargestPrimeFactor使用法から推測されます。F# コンパイラは、上から下への方法で型の推論を実行するため、pおよびn( のパラメーターfindLargestPrimeFactor) の型は、関数での使用法から推論されます。コンパイラが を確認するlet result = ...までに、パラメーターの型は既に として推論されていますint

最も簡単な解決策は、Lすべての定数値にサフィックスを使用することです。そのため、型は次のように推測されint64ます。

let rec findLargestPrimeFactor p n = 
    if n = 1L then p
    else
        if n % p = 0L then findLargestPrimeFactor p (n/p)
        else findLargestPrimeFactor (p + 1L) n

let result = findLargestPrimeFactor 2L 600851475143L

より洗練されたソリューションが必要な場合は、LanguagePrimitivesモジュールの一般的な 1 定数と 0 定数を使用できます。これによりfindLargestPrimeFactor、ジェネリック(-ish)にすることができるため、さまざまな数値型でより簡単に再利用できます。

open LanguagePrimitives

let rec findLargestPrimeFactor p n = 
    if n = GenericOne then p
    else
        if n % p = GenericZero then findLargestPrimeFactor p (n/p)
        else findLargestPrimeFactor (p + GenericOne) n

(* You can use one of these, but not both at the same time --
   now the types of the _arguments_ are used to infer the types
   of 'p' and 'n'. *)

//let result = findLargestPrimeFactor 2L 600851475143L
let result = findLargestPrimeFactor 2 Int32.MaxValue

@kvbの提案に従って、この関数を一般的に記述する方法は次のとおりです。

open LanguagePrimitives

let inline findLargestPrimeFactor p n =
    let rec findLargestPrimeFactor p n =
        if n = GenericOne then p
        else
            if n % p = GenericZero then findLargestPrimeFactor p (n/p)
            else findLargestPrimeFactor (p + GenericOne) n
    findLargestPrimeFactor p n

(* Now you can call the function with different argument types
   as long as the generic constraints are satisfied. *)
let result = findLargestPrimeFactor 2L 600851475143L
let result' = findLargestPrimeFactor 2 Int32.MaxValue
于 2013-02-21T17:41:05.270 に答える