Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Types 可以将窄类型与Fsharp一起使用吗?_Types_F# - Fatal编程技术网

Types 可以将窄类型与Fsharp一起使用吗?

Types 可以将窄类型与Fsharp一起使用吗?,types,f#,Types,F#,我会认为这是一件小事,但我已经花了一些时间在这件事上,仍然没有干净的方法来做: 我有这样一种类型: type EngineTypes = | Petrol | Diesel | Kerosene 我有一大堆函数来处理这些问题 我想制作一个更窄的类型,并且仍然使用这个新类型的原始函数 type ValidEngineType = | Petrol | Diesel 我实现这一目标的唯一方法是: type ValidEngineType = | Valid of engi

我会认为这是一件小事,但我已经花了一些时间在这件事上,仍然没有干净的方法来做:

我有这样一种类型:

type EngineTypes =
 | Petrol
 | Diesel
 | Kerosene 
我有一大堆函数来处理这些问题

我想制作一个更窄的类型,并且仍然使用这个新类型的原始函数

type ValidEngineType =
 | Petrol
 | Diesel
我实现这一目标的唯一方法是:

  type ValidEngineType =
    | Valid of engine : EngineType 
    | NotValid

  let validEngineCheck (engine): ValidEngineType =
    match region with 
    | "petrol" -> Valid EngineType.Petrol
    | "diesel" -> Valid EngineType.Diesel
    | _ -> Invalid
后面的代码:

let myEngine = "petrol"

let checkEngine:Option<EngineType> = 
  match (validEngineCheck myEngine) with
  | Valid engine -> Some engine
  | Invalid -> 
      Console.Error.WriteLine("Unsupported engine: {0}", myEngine);
      None

if checkEngine.IsNone then
  Console.Error.WriteLine("Unsupported engine type")
  Environment.Exit 1

// it is now safe to call this
callingOriginalCode checkEngine.Value
让myEngine=“汽油机”
让checkEngine:选项=
匹配(ValidEngine检查myEngine)与
|有效引擎->某些引擎
|无效->
WriteLine(“不支持的引擎:{0}”,myEngine);
没有一个
如果选中Engine.IsNone,则
Console.Error.WriteLine(“不支持的引擎类型”)
环境。出口1
//现在可以称之为安全
callingOriginalCode检查引擎。值
有没有更简单的方法来管理

更新1:

在ADA中,这称为约束子类型


您要做的是在值构造函数的子集上以任意方式处理求和类型

可以显式建模子集并将其嵌入到超集中:

type ValidEngineTypes = Petrol | Diesel
type EngineType = Valid of ValidEngineTypes | Kerosene
(您可以对OO接口和继承做一些类似的事情,但让我们把它放在一边)

如果组合在很大程度上是任意的,并且彼此不一致,那么可以显式地为每个类型建模,然后使用Choice创建“sum”类型

type Petrol = Petrol
type Diesel = Diesel
type Kerosene = Kerosene

type EngineTypes = Choice<Petrol,Diesel,Kerosene>
type ValidEngineTypes = Choice<Petrol,Diesel>
如果您不喜欢使用
ChoiceN
然后直接使用

type EngineTypes = 
    | PetrolEngine of Petrol
    | DieselEngine of Diesel
    | KeroseneEngine of Kerosene

let foo (engine: EngineTypes) = 
    match engine with
    | PetrolEngine _petrol -> "petrol"
    | DieselEngine _diesel -> "diesel"
    | KeroseneEngine _kerosene -> "kerosene"

这里有些东西可以更简洁,或者更习惯,我只是想让它尽可能简单和明确,你想做的是在值构造函数的子集上以任意方式处理求和类型

可以显式建模子集并将其嵌入到超集中:

type ValidEngineTypes = Petrol | Diesel
type EngineType = Valid of ValidEngineTypes | Kerosene
(您可以对OO接口和继承做一些类似的事情,但让我们把它放在一边)

如果组合在很大程度上是任意的,并且彼此不一致,那么可以显式地为每个类型建模,然后使用Choice创建“sum”类型

type Petrol = Petrol
type Diesel = Diesel
type Kerosene = Kerosene

type EngineTypes = Choice<Petrol,Diesel,Kerosene>
type ValidEngineTypes = Choice<Petrol,Diesel>
如果您不喜欢使用
ChoiceN
然后直接使用

type EngineTypes = 
    | PetrolEngine of Petrol
    | DieselEngine of Diesel
    | KeroseneEngine of Kerosene

let foo (engine: EngineTypes) = 
    match engine with
    | PetrolEngine _petrol -> "petrol"
    | DieselEngine _diesel -> "diesel"
    | KeroseneEngine _kerosene -> "kerosene"

另外,这里有些东西可以更简洁,也可以更惯用,我只是想让它尽可能简单明了

看起来你想把你的引擎分成有效的引擎和其他引擎。这对我来说是一项完美的任务。如果您的代码中有字符串输入:

let (|ValidEngine|_|) (engine: string) =
  match engine with // case-sensitive check here
  | "petrol" -> Some EngineTypes.Petrol
  | "diesel" -> Some EngineTypes.Diesel
  | _ -> None
你的代码就变成了

let myEngine = "petrol"
match myEngine with
| ValidEngine engine -> callingOriginalCode engine // it is now safe to call this
| _ ->
    Console.Error.WriteLine("Unsupported engine type")
    Environment.Exit 1

正如您所看到的,活动模式不仅将引擎字符串划分为有效引擎和无效引擎,而且该分区的有效负载也为engine value。因此,
callingOriginalCode
函数将使用原始的
EngineTypes
参数调用,但仅当发动机类型为
Diesel
Petroleum
时,您才希望将发动机划分为有效发动机和其他发动机。这对我来说是一项完美的任务。如果您的代码中有字符串输入:

let (|ValidEngine|_|) (engine: string) =
  match engine with // case-sensitive check here
  | "petrol" -> Some EngineTypes.Petrol
  | "diesel" -> Some EngineTypes.Diesel
  | _ -> None
你的代码就变成了

let myEngine = "petrol"
match myEngine with
| ValidEngine engine -> callingOriginalCode engine // it is now safe to call this
| _ ->
    Console.Error.WriteLine("Unsupported engine type")
    Environment.Exit 1

正如您所看到的,活动模式不仅将引擎字符串划分为有效引擎和无效引擎,而且该分区的有效负载也为engine value。因此,将使用原始的
EngineTypes
参数调用
callingOriginalCode
函数,但仅当发动机类型为
Diesel
Petroleum

validEngineCheck出现输入错误时才会调用该函数。此外,您也不需要在此处输入新类型,您可以返回一个选项或(更好的是,IMO)一个选项,字符串是一条错误消息,其中包含传入的无效文本。validEngineCheck似乎有输入错误。此外,您不需要在此处使用新类型,您可以返回一个选项或(更好,IMO)一个选项,字符串是一条错误消息,其中包含传入的无效文本。谢谢!我不确定它是如何与使用EngineTypes的函数一起工作的。我已经对它进行了修改!我不确定它是如何与接受EngineTypes的函数一起工作的。我已经解释过了Hanks,Sergey,这是一个有趣的问题。@Istvan您当然可以将
EngineTypes
值而不是字符串进行分区,我只是想展示一下示例代码的外观,这绝对有效,我认为这是最短和最好的解决方案。谢谢,Sergey,这是一个有趣的解决方案。@Istvan您当然可以分区
EngineTypes
值而不是字符串,我只是想展示示例代码的外观,这绝对有效,我认为这是最短和最好的解决方案。