让Seq.zip两个F#序列,一个由列表表示,另一个 - 由Seq.filter应用于无限序列:
Seq.initInfinite (fun i -> i)
|> Seq.filter ((>) 3)
|> Seq.zip ["A";"B"]
Run Code Online (Sandbox Code Playgroud)
按预期返回
val it : seq<string * int> = seq [("A", 0); ("B", 1)]
Run Code Online (Sandbox Code Playgroud)
然而,
Seq.initInfinite (fun i -> i)
|> Seq.filter ((>) 2)
|> Seq.zip ["A";"B"]
Run Code Online (Sandbox Code Playgroud)
试图获得可以通过Seq.filter并最终炸毁fsi的不存在的第3个成员:
Error: Enumeration based on System.Int32 exceeded System.Int32.MaxValue.
Run Code Online (Sandbox Code Playgroud)
虽然由字母列表表示的另一个参数暗示只有两个过滤后的元素足以对函数规范执行zip.
如果我们转向Haskell进行实现比较等效
zip ["A","B"] (filter (<2) [0..])
Run Code Online (Sandbox Code Playgroud)
完成没有任何问题
[("A",0),("B",1)]
Run Code Online (Sandbox Code Playgroud)
由于Haskell实现行为看起来直观正确F#Seq.zip实现的观察行为的正当性是什么?
更新:
我没注意到Haskell
zip (filter (<2) [0..]) ["A","B"]
Run Code Online (Sandbox Code Playgroud)
没有像F#那样完成.
结论:不可能实现Zip函数,该函数能够以参数顺序无关的方式压缩已定义和未定义长度的序列.F#Zip实现只是优先于Haskell参数顺序依赖的参数顺序行为的不变量.
在F#我很容易做到
let a = [1 .. 10];;
Run Code Online (Sandbox Code Playgroud)
那为什么我不能这样做
let a = DateTime.Parse("01/01/2012")
let b = DateTime.Parse("01/01/2020")
let dateList = [a .. b]
Run Code Online (Sandbox Code Playgroud)
它给出了一个错误 Type constraint mismatch. The type DateTime is not compatible with type TimeSpan
我们来看一个简单的函数值f1
:
let f1 = printfn "*bind f1*"; fun () -> printfn "f1()"
Run Code Online (Sandbox Code Playgroud)
f1
在FSI中绑定为
*bind f1*
val f1 : (unit -> unit)
Run Code Online (Sandbox Code Playgroud)
并且,被调用,表现如预期
> () |> f1 |> f1;;
f1()
f1()
val it : unit = ()
Run Code Online (Sandbox Code Playgroud)
现在让我们采用类似的函数值,但明确地通用f2<'a>
:
let f2<'a> = printfn "*bind f2*"; fun () -> printfn "f2()"
Run Code Online (Sandbox Code Playgroud)
f2
在FSI中绑定为
val f2<'a> : (unit -> unit)
Run Code Online (Sandbox Code Playgroud)
没有任何*bind f2*
输出,但随后被调用,在每次f2
调用时输出:
> () |> f2 |> f2;;
*bind f2*
f2()
*bind f2*
f2()
val …
Run Code Online (Sandbox Code Playgroud) 在这个问题的背景下被发现这个看似不一致的行为可以在F#2.0和F#3.0 RC中重现:
type Heterogeneous =
static member Echo([<ParamArray>] args: Object[]) = args
type Generic =
static member Echo<'T>([<ParamArray>] args: 'T[]) = args
Run Code Online (Sandbox Code Playgroud)
用法:返回:
Heterogeneous.Echo 0 // [|0|] OK
Generic.Echo 0 // [|0|] OK
Heterogeneous.Echo (0,1) // [|0; 1|] OK
Generic.Echo (0,1) // [|0; 1|] OK
Heterogeneous.Echo [|0|] // [|[|0|]|] OK?
Generic.Echo [|0|] // [|0|] OOPS!!
Heterogeneous.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
Generic.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释观察到的行为是否是一个错误或功能?
更新:
这个相关的答案传达了F#开发团队的一个确认,即现在在处理带ParamArray
属性的泛型类型参数时存在错误.
我正在尝试将一个简单的f#控制台应用程序部署到同事计算机,但它仍然失败.双击应用程序图标后,将出现控制台窗口,但随后出现Microsoft错误报告窗口,询问我是否要发送错误报告,然后拒绝控制台窗口中的某些文本闪烁.它看起来像一个错误消息,但窗口关闭太快而无法分辨.奇怪的是,如果我创建一个类似的C#应用程序,它的工作原理.我在发布模式下瞄准.net 4客户端框架.
这是代码
f#代码(不起作用):
open System
printfn "print test"
Console.ReadLine() |> ignore
Run Code Online (Sandbox Code Playgroud)
c#代码(确实有效):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestCApplication
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Testing...");
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud) 我需要处理一系列毫秒时间帧的历史刻度数据.需要能够过滤某些时间盘(小时,分钟等)的开口刻度.该序列可能具有比跨度更大的间隙,因此必须将这种间隙之后的第一个刻度选为开口,否则开口刻度是最接近相应时间跨度的日历开始的那个.
我想到的第一件事是以下有状态过滤函数opensTimespan:Timespan->(Timestamp->bool)
,它将每个间隙开放或间隔开放的时间间隔捕获到一个闭包中,以便在调用之间传递:
let opensTimespan (interval: Timespan)=
let lastTakenId = ref -1L // Timestamps are positive
fun (tickAt: Timestamp) ->
let tickId = tickAt / interval in
if tickId <> !lastTakenId then lastTakenId := tickId; true
else false
Run Code Online (Sandbox Code Playgroud)
并可以这样应用:
let hourlyTicks = readTicks @"EURUSD-history.zip" "EURUSD-2012-04.csv"
|> Seq.filter (opensTimespan HOUR) |> Seq.toList
Run Code Online (Sandbox Code Playgroud)
这很好,但opensTimespan
副作用绝对不是惯用的.
一种替代方案可能是使用以下事实:对于勾选的决定是打开一个或不需要只需要自己和前一个时间戳的一对来提出以下无状态过滤功能opensTimespanF:Timespan->Timestamp*Timestamp->bool
:
let opensTimespanF interval (ticksPair: Timestamp*Timestamp) =
fst ticksPair/ interval <> snd ticksPair/ interval
Run Code Online (Sandbox Code Playgroud)
可以应用为:
let hourlyTicks=
seq { …
Run Code Online (Sandbox Code Playgroud)