假设我想Option
在async
工作流程中返回一段时间:
let run =
async {
let! x = doAsyncThing
let! y = doNextAsyncThing x
match y with
| None -> return None
| Some z -> return Some <| f z
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,我会使用FSharpx中的可能计算表达式同时作为异步来避免这样做match
.我可以创建一个自定义构建器,但是有没有办法一般地组合两个计算表达式?它可能看起来像这样:
let run =
async {
let! x = doAsyncThing
let! y = doNextAsyncThing x
return! f y
}
Run Code Online (Sandbox Code Playgroud) monads f# asynchronous monad-transformers computation-expression
看看FSharpPlus我正在考虑如何创建一个用于的泛型函数
let qr0 = divRem 7 3
let qr1 = divRem 7I 3I
let qr2 = divRem 7. 3.
Run Code Online (Sandbox Code Playgroud)
并提出了一个可能的(工作)解决方案
let inline divRem (D:^T) (d:^T): ^T * ^T = let q = D / d in q, D - q * d
Run Code Online (Sandbox Code Playgroud)
然后我看了FSharpPlus如何实现它,我发现:
open System.Runtime.InteropServices
type Default6 = class end
type Default5 = class inherit Default6 end
type Default4 = class inherit Default5 end
type Default3 = class inherit Default4 end
type Default2 = class inherit Default3 end …
Run Code Online (Sandbox Code Playgroud) 我想IEnumerable<KeyValuePair<DateTime, 'T>>
在我自己的类中实现并向该类添加数学运算符,以便运算符可以像任何数值类型的内联函数一样工作'T
- 自动添加约束.
我只是无法使下面的代码工作.在成员声明中,它既不能使用也不能使用'inline'关键字.
另外,如果我定义一个函数
let inline add l r = l + r
Run Code Online (Sandbox Code Playgroud)
在类型之前使用它而不是添加l.Value + r.Value,它也不起作用.
有人可以告诉我我做错了什么吗?
可能整个方法都是错误的,并且有另一种方法可以实现相同的目标吗?
namespace Test
open System
open System.Linq
open System.Collections.Generic
[<SerializableAttribute>]
type TimeSeries<'T>(dictionary : IDictionary<DateTime, 'T>) =
let internalList = new SortedList<DateTime, 'T>(dictionary)
interface IEnumerable<KeyValuePair<DateTime, 'T>> with
member this.GetEnumerator() = internalList.GetEnumerator()
member this.GetEnumerator() : Collections.IEnumerator
= internalList.GetEnumerator() :> Collections.IEnumerator
member private this.sl = internalList
static member inline (+) (left : TimeSeries<'T>, right : TimeSeries<'T>) =
let res =
query …
Run Code Online (Sandbox Code Playgroud) 我正在调用外部函数需要float[]
,但我的数组是float<m>[]
。如何从数组中去除度量单位?
我需要类似下面的函数,但这不能编译。我想避免数组的任何迭代或重复,因为float<m>
和float
值是相同的......
let demeasure (arr:float<m>[]): float[] = float[] (arr)
Run Code Online (Sandbox Code Playgroud) 绅士们,
过去的程序/确定性程序员与 F# 函数式斗争......
我需要一些计数器来记录程序各个区域的计数。以下代码编译干净并且似乎可以工作,但“ctr”永远不会增加。
任何帮助表示赞赏,伊恩
type Count() as this =
let mutable ctr = 0
do
printfn "Count:Constructor: %A" ctr
member this.upctr : int =
let ctr = ctr + 1
printfn "inCount.upctr %d" ctr
ctr
let myCount = new Count()
printfn "MyCtr1 %d" (myCount.upctr)
let fred = myCount.upctr
let fred = myCount.upctr
Run Code Online (Sandbox Code Playgroud) 我傻吗?有些东西在 monad/计算表达式中看起来更好,我有很多使用 seq 计算表达式的代码,但是每次我点击一个选项<>我都必须恢复到“Option.map”等。
有点刺耳(当我在 C# 中执行此操作时,我为 IMaybe<> 类型编写了一个 linq 运算符,它看起来不错且一致)。
我可以,但不是特别想写一个,那里肯定有一个(或多个),人们使用哪个?
IE
所以而不是
let postCodeMaybe =
personMaybe
|> Option.bind (fun p -> p.AddressMaybe())
|> Option.map (fun -> p.Postcode())
Run Code Online (Sandbox Code Playgroud)
我们可以去
let postCodeMaybe =
option {
for p in personMaybe do
for a in p.AddressMaybe() do
a.Postcode()
}
Run Code Online (Sandbox Code Playgroud)
我对前面的代码没有任何问题,除了在我的上下文中它存在于许多看起来像后者的“seq”计算表达式中(并且一些将查看此代码的开发人员将来自 C#/LINQ 背景,这些背景基本上是后者)。
绑定策略ContT
忽略内部monad,实际上代码与for相同Cont
.
按照其他Monad变形金刚的比喻,我会以这种方式实现它:
return x = ContT ($ (return x))
(>>=) x f = ContT (\k -> runContT x ((=<<) (\a -> runContT (f a) k)))
Run Code Online (Sandbox Code Playgroud)
然后例如这个表达式:
do
x1 <- ContT (\k -> k [1, 2])
x2 <- ContT (\k -> k [10, 20])
return ((+) x1 x2)
Run Code Online (Sandbox Code Playgroud)
会导致 [11, 21, 12, 22]
我的问题是设计决策背后的原因是什么?为什么它以这种方式实现,这使得它与其他Monad Transformers非常不同,请注意functor实例是:
fmap f m = ContT $ \c -> runContT m (c . f)
Run Code Online (Sandbox Code Playgroud)
而不是:
fmap f m = ContT $ runCont $ …
Run Code Online (Sandbox Code Playgroud) 我有一个运行良好的示例铁路管道:
open FSharpPlus
let funA n =
if n < 10 then Ok n
else Error "not less than 10"
let funB n =
if n < 5 then Ok (n, n * 2)
else Error "not less than 5"
let funC n = // int -> Result<(int * int), string>
n
|> funA
>>= funB // it works
Run Code Online (Sandbox Code Playgroud)
但是,当我想将其funB
转换为异步功能时,出现了编译错误。从逻辑上讲,它应该没有什么不同。相同的输出/输入...怎么了?
应该做些什么才能使其正常工作?
open FSharpPlus
let funA n =
if n < 10 then Ok n
else Error "not less …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用任务并行库对树进行求和,其中只生成子任务,直到遍历树直到某个深度,否则它使用延续传递样式对剩余的子节点求和,以避免堆栈溢出.
但是,代码看起来很丑陋 - 使用状态monad来承载当前深度会很好,但状态monad不是尾递归.或者,我如何修改继续monad来携带状态?或者创建状态和延续monad的组合?
let sumTreeParallelDepthCont tree cont =
let rec sumRec tree depth cont =
let newDepth = depth - 1
match tree with
| Leaf(num) -> cont num
| Branch(left, right) ->
if depth <= 0 then
sumTreeContMonad left (fun leftM ->
sumTreeContMonad right (fun rightM ->
cont (leftM + rightM )))
else
let leftTask = Task.Factory.StartNew(fun () ->
let leftResult = ref 0
sumRec left newDepth (fun leftM ->
leftResult := leftM)
!leftResult
)
let rightTask = …
Run Code Online (Sandbox Code Playgroud) 我试图理解读者单子转换器。我正在使用FSharpPlus并尝试编译以下示例,该示例首先从阅读器环境中读取某些内容,然后执行一些异步计算,最后合并两个结果:
open FSharpPlus
open FSharpPlus.Data
let sampleReader = monad {
let! value = ask
return value * 2
}
let sampleWorkflow = monad {
do! Async.Sleep 5000
return 4
}
let doWork = monad {
let! envValue = sampleReader
let! workValue = liftAsync sampleWorkflow
return envValue + workValue
}
ReaderT.run doWork 3 |> Async.RunSynchronously |> printfn "Result: %d"
Run Code Online (Sandbox Code Playgroud)
有了这个,我在它显示的行出现编译错误,let! value = ask
并显示以下完全无用的(至少对我来说)错误消息:
将默认类型“obj”应用于类型推断变量时,类型约束不匹配。没有与方法“op_GreaterGreaterEquals”匹配的重载。
已知返回类型:异步
已知类型参数:< obj , (int -> Async) >
感觉就像我只是在某个地方缺少一些操作员,但我无法弄清楚。
假设我有一些返回的函数Async<Result<string>>
:
let getData id = async {
return Ok (string id)
}
Run Code Online (Sandbox Code Playgroud)
现在,此函数的输入是另一个返回函数的结果Result<int>
.
我正在努力研究如何Result.bind
在异步CE内部组合2 .
例如:
let main = async {
let id = Ok 123
let! x = id |> Result.bind getData
return x
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,我收到错误:
error FS0001: Type mismatch. Expecting a
'Result<int,'a> -> Async<'b>'
but given a
'Result<int,'a> -> Result<'c,'a>'
Run Code Online (Sandbox Code Playgroud)
或者如果我不使用let!
我得到并且只是使用let
error FS0001: Type mismatch. Expecting a
'int -> Result<'a,'b>'
but given a
'int -> Async<Result<string,'c>>
Run Code Online (Sandbox Code Playgroud)
我见过一些答案是说没有使用Result<'a>
,只是让异步异常处理做了艰苦的工作,但我面对同样的问题 …
有人可以解释一下这段代码在 F# 中的工作原理吗:
https://github.com/fsprojects/FSharpPlus/blob/master/src/FSharpPlus/Control/Functor.fs#L99-99
static member inline Invoke (mapping: 'T->'U) (source: '``Functor<'T>``) : '``Functor<'U>`` =
let inline call (mthd: ^M, source: ^I, _output: ^R) = ((^M or ^I or ^R) : (static member Map : (_*_)*_ -> _) (source, mapping), mthd)
call (Unchecked.defaultof<Map>, source, Unchecked.defaultof<'``Functor<'U>``>)
Run Code Online (Sandbox Code Playgroud)
具体来说call
,该函数使用了我不理解的语法
例如
(^M or ^I or ^R)
意思?... -> 'a
当它似乎返回一个元组时,它如何具有类型签名?f# ×11
f#+ ×4
monads ×2
arrays ×1
asynchronous ×1
class ×1
constraints ×1
continuation ×1
counter ×1
generics ×1
haskell ×1
state ×1