在Haskell中是否有惯用的方式来表达以下代码?
//using it without latestWith - lets me autocomplete but requires
//typing first
import { CityService } from "../services/city-list.service";
import { Component, OnInit, OnDestroy } from "@angular/core";
import { City } from "../models/city";
import { Subscription, Observable } from "rxjs";
import {
map,
filter,
startWith,
withLatestFrom,
debounceTime
} from "rxjs/operators";
import {
FormGroup,
FormControl,
FormBuilder,
Validators,
NgForm,
Form
} from "@angular/forms";
@Component({
selector: "app-city-list",
templateUrl: "./city-list.component.html",
styleUrls: ["./city-list.component.css"]
})
export class CityListComponent implements OnInit {
cities: City[];
citySub: Subscription;
destinationCitySub: Observable<City[]>;
originCitySub: Observable<City[]>;
instantFlightForm: FormGroup;
constructor(public cityService: CityService, private fb: FormBuilder) {
}
ngOnInit() {
this.instantFlightForm = this.fb.group({
destinationCity: [""],
originCity: ["", Validators.required],
startDate: []
});
this.cityService.getCities();
this.citySub = this.cityService.getCityUpdateListener().subscribe(c=>this.cities=c);
this.destinationCitySub = this.valueChange('destinationCity');
}
private valueChange(string) {
return this.instantFlightForm.get(string).valueChanges.pipe(
// withLatestFrom(this.cities),
debounceTime(100),
map((term) => {
console.log(term);
return this._filter(term);
})
);
}
private _filter(term): City[] {
const filterValue = term.toLowerCase();
return this.cities.filter(option =>
option.name.toLowerCase().includes(filterValue)
);
}
onInstantSearch(form: FormGroup) {
console.log(form.value);
}
}
这段代码非常冗长,所以我可能做得很奇怪。
答案 0 :(得分:8)
fix . (>>=) :: IO a -> IO b
比较forever
,即State1
。
编辑:仅在State2
= State3
= data-fix
时有效。如果没有,main = fix (traverse unFix >=>)
[ana runService1 initState1, ana runService2 initState2, ana runService3 initState3]
允许:
{{1}}
答案 1 :(得分:4)
我练习,您可能希望将该状态添加到合适的 state monad 中。 StartDate = meetingRequest.Start.ToString();
TimeZone = meetingRequest.TimeZone;
var AllTimeZones = TimeZoneInfo.GetSystemTimeZones();
foreach (TimeZoneInfo timeZoneInfo in AllTimeZones) {
if (timeZoneInfo.ToString() == TimeZone) {
TimeZoneInfo ActualTimeZone = timeZoneInfo;
var MeetingWindowStartDate = TimeZoneInfo.ConvertTime(
meetingRequest.Start,
ActualTimeZone,
service.TimeZone);
}
库使访问它变得容易:
lens
这样,这并不能使您在原始代码上花很多钱,但是如果您还给{-# LANGUAGE TemplateHaskell #-}
import Control.Lens.TH
import Control.Monad.Trans.State
data AllState = AllState { _s₀ :: State0, _s₁ :: State1, _s₂ :: State2 }
makeLenses ''AllState
loop :: StateT AllState IO ()
loop = do
s₀ <~ runService0 <$> use s₀
s₁ <~ runService1 <$> use s₁
s₂ <~ runService2 <$> use s₂
loop
main = evalStateT loop $ AllState initState0 initState1 initState2
动作指定合适的状态单调类型,它将变得更加方便:
runService
...然后您可以简单地使用zoom
机制:
runService0 :: StateT State0 IO ()
runService1 :: StateT State1 IO ()
runService2 :: StateT State2 IO ()
或正如古尔肯格拉斯的建议
loop :: StateT AllState IO ()
loop = do
zoom s₀ runService0
zoom s₁ runService1
zoom s₂ runService2
loop
答案 2 :(得分:0)
该解决方案不是更简洁,但是解决了原始表述的模糊性:每个过程的“展开”与所有过程的“拉锁在一起”混合在一起。如果我们可以独立定义每个流程,然后在我们认为合适的时候将它们合并,那就太好了。
我们需要以下辅助类型:
newtype Iter = Iter (IO Iter)
unfoldIter :: (s -> IO s) -> s -> Iter
unfoldIter f s = Iter (unfoldIter f <$> f s)
runIter :: Iter -> IO ()
runIter (Iter action) = action >>= runIter
doNothingIter :: Iter
doNothingIter = unfoldIter return ()
zipIter :: Iter -> Iter -> Iter
zipIter (Iter action1) (Iter action2) =
Iter (zipIter <$> action1 <*> action2)
instance Monoid Iter where
mempty = doNothingIter
mappend = zipIter
然后loop
变为:
loop :: State1 -> State2 -> State3 -> IO ()
loop s1 s2 s3 =
runIter $ unfoldIter runService1 s1
<> unfoldIter runService2 s2
<> unfoldIter runService3 s3
如果我们不想定义自己的辅助类型,可以使用提供“压缩”操作的流式库,例如streaming。