我最近提出了一个有趣的问题,流利的方法应该返回什么?他们应该改变当前对象的状态还是创建一个具有新状态的全新对象?
如果这个简短描述不是非常直观,这是一个(不幸的)冗长的例子.这是一个计算器.它执行非常繁重的计算,这就是他通过异步回调返回结果的原因:
public interface ICalculator {
// because calcualations are too lengthy and run in separate thread
// these methods do not return values directly, but do a callback
// defined in IFluentParams
void Add();
void Mult();
// ... and so on
}
Run Code Online (Sandbox Code Playgroud)
所以,这是一个设置参数和回调的流畅界面:
public interface IFluentParams {
IFluentParams WithA(int a);
IFluentParams WithB(int b);
IFluentParams WithReturnMethod(Action<int> callback);
ICalculator GetCalculator();
}
Run Code Online (Sandbox Code Playgroud)
这个接口实现有两个有趣的选项.我将展示它们,然后我会写出我发现它们各自的好坏.
因此,首先是普通,它返回此:
public class FluentThisCalc : IFluentParams {
private int? _a;
private int? _b;
private Action<int> _callback;
public …Run Code Online (Sandbox Code Playgroud) 我想给一个printf函数一个元组:
let tuple = ("Hello", "world")
do printfn "%s %s" tuple
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,编译器首先说,它需要string而不是string*string.我写的如下:
let tuple = ("Hello", "world")
do printfn "%s %s" <| fst tuple
Run Code Online (Sandbox Code Playgroud)
然后编译器合理地注意到现在我有类型的函数值string -> unit.说得通.我可以写
let tuple = ("Hello", "world")
do printfn "%s %s" <| fst tuple <| snd tuple
Run Code Online (Sandbox Code Playgroud)
它对我有用.但我想知道,如果有任何方法可以做得更好,就像
let tuple = ("Hello", "world")
do printfn "%s %s" <| magic tuple
Run Code Online (Sandbox Code Playgroud)
我的问题是我无法获得printf需要哪种类型以便打印两个参数.什么magic功能看起来像?
我真的很喜欢F#的async工作流程,但就我而言,它有一个严重的问题:它不允许创建应该执行不超过某个特定时间跨度的工作流程.
为了更清楚,这是我为自己写的一个简单的函数:
let withTimeout operation timeout = async {
try
return Some <| Async.RunSynchronously (operation, timeout)
with :? TimeoutException -> return None
}
Run Code Online (Sandbox Code Playgroud)
即签名是
val withTimeout : operation:Async<'a> -> timeout:int -> Async<'a option>
Run Code Online (Sandbox Code Playgroud)
示例用法:
let op = async {
do! Async.Sleep(1000)
return 1
}
#time
withTimeout op 2000 |> Async.RunSynchronously;;
// Real: 00:00:01.116, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
// val it : unit option = Some 1
withTimeout op 2000 |> Async.RunSynchronously;;
// Real: …Run Code Online (Sandbox Code Playgroud) 让我感到沮丧的代码如下:
bool a = 0x00000FF0 & 0x00000FF0 == 0x00000FF0;
if (a) {
Serial.println("True");
} else {
Serial.println("False");
}
Run Code Online (Sandbox Code Playgroud)
这打印"假".我真的不明白为什么.更多测试:
bool a = 0x00000FF0 & 0x00000FF0 == 0x00000FF0;
Serial.println(a);
Run Code Online (Sandbox Code Playgroud)
打印0.
和:
unsigned long a = 0x00000FF0 & 0x00000FF0;
Serial.println(a, HEX);
Run Code Online (Sandbox Code Playgroud)
打印FF0.
我使用反射用数据填充一些对象的字段.由于我的对象是F#类型,它有一些Option字段.如有选择权
property.SetValue(object, newValue)
Run Code Online (Sandbox Code Playgroud)
合理地失败,因为它需要
property.SetValue(object, Some(newValue))
Run Code Online (Sandbox Code Playgroud)
因此,我试图找出一个属性是否类型Option.我可以这样做:
let isOption (p:PropertyInfo) = p.PropertyType.Name.StartsWith("FSharpOption")
Run Code Online (Sandbox Code Playgroud)
但必须有更好的方法,不是吗?我必须说,这是奇怪,我有没有方法IsOption在FSharpType.
我无法理解为什么会这样
let data =
JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(
File.ReadAllText <| Path.Combine(myPath, "ejv.json"))
Run Code Online (Sandbox Code Playgroud)
没关系,而这个
let data =
JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>
<| File.ReadAllText
<| Path.Combine(myPath, "ejv.json")
Run Code Online (Sandbox Code Playgroud)
给我两个错误,首先是:

第二是:

我做错了什么?
UPDATE @PatrykĆwiek提出了一个很好的编辑,它似乎修复了类型的错误:
let data = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>
<< File.ReadAllText
<| Path.Combine(myPath, "ejv.json")
Run Code Online (Sandbox Code Playgroud)
但它产生了另一个令人费解的消息:意外的类型参数.这是一个截图:

我可以很容易地删除它删除<Dictionary<string, Dictionary<string, string>>>但在这种情况下我的数据是object类型,而不是Dictionary.我可以以某种方式保存类型信息使用流水线吗?
解
感谢@PatrykĆwiek解决方案如下:
let d<'a>(s:string) = JsonConvert.DeserializeObject<'a>(s)
let data =
Path.Combine(myPath, "ejv.json")
|> File.ReadAllText
|> d<Dictionary<string, Dictionary<string, string>>> with
Run Code Online (Sandbox Code Playgroud)
我不知道为什么,但没有别名d它不起作用.
在我的MS Excel中,我对不同数据类型的舍入操作有不同的行为:
如果是单身:
? Application.Round(6.575!, 2)
6.57
Run Code Online (Sandbox Code Playgroud)
如果是Double:
? Application.Round(6.575#, 2)
6.58
Run Code Online (Sandbox Code Playgroud)
有人知道为什么吗?
更新:@paxdiablo给出了一个很好的答案,所以只是为了在这里重现它:
在单精度中,6.575是二进制表示的0 10000001 101001 0011 0011 0011 0011,或6.57499980926513671875.这轮到6.57
在双精度中,增加了更多的0011,它们的重量足以使数量略大于6.575(6.57500000000000017763568394003),因此它将达到6.58
在Perl语言中,人们可以写出类似的内容
someFunction() if $x == 0
Run Code Online (Sandbox Code Playgroud)
即在后缀表示法中应用条件.
我确信在F#中必须有类似的表达式,因为它在处理函数时非常灵活.但是当我试着写的时候
someFunction() if x = 0
Run Code Online (Sandbox Code Playgroud)
要么
someFunction() << if x = 0
Run Code Online (Sandbox Code Playgroud)
我收到了预期的错误消息.有没有办法在F#中实现更多或更少的通用后缀条件运算符?
我的问题受到这个问题的启发:链接
这是一个代码:
type A =
| X of int * int
| Y of string
let f (A.X(a, b)) = a + b
Run Code Online (Sandbox Code Playgroud)
它有效,但有警告:

说得通; 我和Y没有比赛.
但是,如果我添加一行
let f (A.Y(s)) = 10
Run Code Online (Sandbox Code Playgroud)
然后我收到一个错误:

有没有一种很好的方法来修复它并仍然在函数参数中使用模式匹配?如果没有,那么为什么他们会创建这样奇怪的语法,这总是会引发警告?
f# ×7
.net ×2
asynchronous ×1
c ×1
c# ×1
c++ ×1
collections ×1
excel ×1
excel-vba ×1
generics ×1
immutability ×1
java ×1
math ×1
oop ×1
operators ×1
pipeline ×1
reflection ×1
timeout ×1
tuples ×1
vba ×1