inline在我看来,F#中的关键字与我在例如C中使用的目的有些不同.例如,它似乎影响函数的类型(什么是"静态解析的类型参数"?不是所有的F#类型静态解决?)
我inline什么时候应该使用功能?
Haskell版本(1.03s):
module Main where
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Control.Monad
import Control.Applicative ((<$>))
import Data.Vector.Unboxed (Vector,(!))
import qualified Data.Vector.Unboxed as V
solve :: Vector Int -> Int
solve ar =
V.foldl' go 0 ar' where
ar' = V.zip ar (V.postscanr' max 0 ar)
go sr (p,m) = sr + m - p
main = do
t <- fmap (read . T.unpack) TIO.getLine -- With Data.Text, the example finishes 15% faster.
T.unlines . map (T.pack …Run Code Online (Sandbox Code Playgroud) 我对F#很陌生,发现类型推断确实很酷.但目前似乎它也可能导致代码重复,这不是一件很酷的事情.我想总结一个这样的数字的数字:
let rec crossfoot n =
if n = 0 then 0
else n % 10 + crossfoot (n / 10)
crossfoot 123
Run Code Online (Sandbox Code Playgroud)
这正确打印6.但是现在我的输入数字不适合32位,所以我必须将其转换为.
let rec crossfoot n =
if n = 0L then 0L
else n % 10L + crossfoot (n / 10L)
crossfoot 123L
Run Code Online (Sandbox Code Playgroud)
然后,BigInteger我来了,猜猜是什么......
当然,我只能提供bigint版本和转换输入参数,并根据需要输出参数.但首先我假设使用BigInteger过度int有一些性能惩罚.第二个let cf = int (crossfoot (bigint 123))不好看.
写这个没有通用的方法吗?
有没有办法约束一个类型参数从另一个派生?
type Foo<'T, 'U when 'U :> 'T> =
member x.Bar() : 'T = upcast Unchecked.defaultof<'U>
Run Code Online (Sandbox Code Playgroud)
此代码产生以下错误:
错误1无效约束:用于约束的类型是密封的,这意味着约束只能通过最多一个解决方案来满足
错误2此类型参数的使用方式将其限制为始终为"T"
错误3从类型'T到'T0的静态强制涉及基于此程序点之前的信息的不确定类型.某些类型不允许静态强制.需要进一步的类型注释.
警告4此构造使代码不如类型注释所指示的那样通用.类型变量'U已被约束为类型''T'.
在C#中,我可以为类型为T的泛型数组定义一个扩展方法,如下所示:
public static T GetOrDefault<T>(this T[] arr, int n)
{
if (arr.Length > n)
{
return arr[n];
}
return default(T);
}
Run Code Online (Sandbox Code Playgroud)
但对于我的生活,我无法弄清楚如何在F#中做同样的事情!我试过了type 'a array with,type array<'a> with并且type 'a[] with编译器对它们中的任何一个都不满意.
任何人都可以告诉我在F#中做到这一点的权利是什么?
当然,我可以通过掩盖阵列模块并为此轻松添加功能来实现这一点,但我真的想知道如何将其作为扩展方法!
我很困惑如何将函数标记为泛型而没有类似的显式类型声明 ('a -> 'a)
let add a b = a + b
Run Code Online (Sandbox Code Playgroud)
这给了我们
val add : a:int -> b:int -> int
Run Code Online (Sandbox Code Playgroud)
但是我们可以立即打电话
add "Hello " "World!"
Run Code Online (Sandbox Code Playgroud)
现在add的值是
val add : a:string -> b:string -> string
val it : string = "Hello World!"
Run Code Online (Sandbox Code Playgroud)
如果我们再打电话
add 2 3 // then we get
error: This expression was expected to have type string but here has type int
Run Code Online (Sandbox Code Playgroud)
如何确保函数适用于所有已(+)定义函数的类型
暂且不管我们是否应该使用度量单位来表示像角度这样的无单位概念,假设我在F#中定义了单位degree和radian单位
type [<Measure>] degree =
static member ToRadians (d:float<degree>) : float<radian> = d * (Math.PI * 1.<radian>) / 180.0<degree>
and [<Measure>] radian =
static member ToDegrees (r:float<radian>) : float<degree> = r * 180.0<degree> / (Math.PI * 1.<radian>)
Run Code Online (Sandbox Code Playgroud)
我可以比较容易地使用它们
4.0<degree> |> degree.ToRadians
Run Code Online (Sandbox Code Playgroud)
看起来扩展成员会更加方便.所以我可以说
let d = 4.0<degree>
let r = d.ToRadians()
Run Code Online (Sandbox Code Playgroud)
但我无法以明显的方式定义扩展成员
type float<degree> with
member degrees.ToRadians() = degree.ToRadians(degrees)
Run Code Online (Sandbox Code Playgroud)
...这让我有以下错误
error FS0010: Unexpected identifier in type name. Expected infix operator, quote symbol or other token.
Run Code Online (Sandbox Code Playgroud)
对于F#中的度量单位,是否存在扩展成员的语法技巧,或者是否支持该功能?
我正在尝试在F#中实现duck typing,我发现你可以在F#泛型中有一个成员约束,如下所示:
type ListEntryViewModel<'T when 'T : (member Name : string)>(model:'T) =
inherit ViewModelBase()
member this.Name with get() = model.Name
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试引用该属性时,上面的代码将无法编译.我收到编译器错误:
此代码不够通用.^ T :(成员get_Name:^ T - >字符串)时的类型变量^ T无法一般化,因为它会逃避其范围.
是否可以通过通用约束实现鸭子类型?
我试图在F#中使用显式成员约束.文档说"F#支持公共语言运行库支持的完整约束集",但是如果我实际上编译了一个具有这种显式约束的类,比如下面的那样,我就会遇到异乎寻常的错误.
type MyType<'T when ^T: (static member ( + ) : ^T * ^T -> ^T)> =
member this.F a b = a + b
Run Code Online (Sandbox Code Playgroud)
报告
错误FS0670:此代码不够通用.当^ T :(静态成员(+):^ T*^ T - > ^ T)时,类型变量^ T无法推广,因为它会逃避其范围.
并在定义网站上报告member this.F.这是什么意思?相关范围是什么?
这种语言支持许多方法来完成这类工作.可以在StackOverflow上找到一个很好的探索,但是我没有看到为什么不允许这种特殊的通用约束"逃避"的明确解释.
请解释drawShape功能背后的魔力.1)为什么它可以工作 - 我的意思是它如何称呼Draw成员,2)它为什么需要inline?
type Triangle() =
member x.Draw() = printfn "Drawing triangle"
type Rectangle() =
member x.Draw() = printfn "Drawing rectangle"
let inline drawShape (shape : ^a) =
(^a : (member Draw : unit->unit) shape)
let triangle = Triangle()
let rect = Rectangle()
drawShape triangle
drawShape rect
Run Code Online (Sandbox Code Playgroud)
接下来的问题是 - 是否可以drawShape使用如下所示的参数类型注释来编写函数?我发现它与第一个签名完全相同,但我无法完成身体.
let inline drawShape2 (shape : ^a when ^a : (member Draw : unit->unit)) =
...
Run Code Online (Sandbox Code Playgroud)
提前致谢.