Как восстановить голову и хвост кортежа в F # - PullRequest
0 голосов
/ 07 ноября 2011
  1. Как получить голову и хвост кортежа в F #?

    Например, Conj (a, b), голова Conj, хвост (a, b).

  2. Я хочу рекурсивно запустить функцию buildtree для каждого параметра, поместить голову как элемент Node, где карта в F #?

    let rec getparams = map List.head (List.tail getparams);
    
    type Elem = Prop
    type Tree = E | T of Elem * Tree * Tree
    
    let rec buildtree vars = function
        | E = head vars
        | T = buildtree (getparams vars)
    

После обновления:

open System
open Microsoft.FSharp.Reflection
// Learn more about F# at http://fsharp.net
//type Prop = {a: string; b: string}
//let Prop a b = (a, b) 
type Op = Prop
type tree = E | T of Op * tree * tree
let tree x y z = (x, y, z)

type binOp = Conj | Disj | Impl 
type expr =   
| Prop of string   
| BinOp of binOp * expr * expr 
| Conj of expr * expr
| Disj of expr * expr
| Impl of expr * expr

type Prop = {a: string}
let Prop a = (a)

//type Conj = {a : Prop; b : Prop} 
let Conj a b = (a, b)

//type Conj_Int = {a : Prop; b : Prop} 
let Conj_Int a b = Conj a b
//type Conj_Elmin1 = {a : Conj}
let Conj_Elmin1 a = fst a
//type Conj_Elmin2 = {a : Conj}
let Conj_Elmin2 a = snd a

//type Impl = {a : Prop; b : Prop} 
let Impl a b = (a b)
//type Impl_Int = {assume : Prop; b : Prop} 
let Impl_Int assume b = Impl assume b
//type Impl_Elmin = {a :string; b : Impl}
let Impl_Elmin a b = if a = fst b then snd b

type Neg = {a : Prop;}
let Neg a = (a)

//type Double_Neg_Int = {a : Prop;}
let Double_Neg_Int a = Neg(Neg(a))

//type Double_Neg_Elmin = {a : Prop}
let Double_Neg_Elmin a = fst(fst(a))

//type Disj = {a : Prop; b : Prop} 
let Disj a b = (a,b)

//type Disj_Int1 = {a : Prop; b : Prop} 
let Disj_Int1 a b = (a b)
//type Disj_Int2 = {a : Prop; b : Prop} 
let Disj_Int2 a b = (a b)

//type Disj_Elmin1 = {a : Disj}
let Disj_Elmin1 a = fst(a)
//type Disj_Elmin2 = {a : Disj}
let Disj_Elmin2 a = snd(a)

type TupleSplitter = static member splitTuple (a,b,c) = (a,(b,c)) 

let tupleToList t = if Microsoft.FSharp.Reflection.FSharpType.IsTuple(t.GetType()) then Some (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields t |> Array.toList) else None
    let operation x = List.head(List.ofSeq(FSharpValue.GetTupleFields(x)))
let parameters x = List.tail(List.ofSeq(FSharpValue.GetTupleFields(x)))


let rec map f = function | Prop _ as t -> f t | BinOp(op, a, b) -> f(BinOp(op, map f a, map f b))
(*
let rec map f = function   
| Prop _ as t -> f t   | Conj(a, b) -> f(Conj(map f a, map f b))   
| Disj(a, b) -> f(Disj(map f a, map f b))   
| Impl(a, b) -> f(Impl(map f a, map f b)) 
*)
let buildtree vars expr = map (function Prop v -> Map.find v vars | expr -> expr) expr 

let t = buildtree(Conj("a","b"))
  1. как иметь два типа выражения Op * Tree * Tree и Op * Tree?

Ответы [ 3 ]

5 голосов
/ 07 ноября 2011

Как сказал Анкур, вы не можете получить головку и хвост кортежа - эти операции предназначены для обработки функциональных списков, которые имеют произвольную длину и не могут быть определены для кортежей, длина которых известна во время компиляции. Если вам нужны данные произвольной длины, вам, вероятно, следует использовать кортежи и сопоставление с образцом (или List.head и List.tail).

Если вам действительно нужно динамически обрабатывать кортежи, вы можете использовать отражение F #:

open Microsoft.FSharp.Reflection

(1,2,3)
|> FSharpValue.GetTupleFields // Get fields of tuple as an array
|> List.ofSeq                 // Convert array to a list
|> List.tail                  // Now you can process list using head/tail

Тем не менее, обратите внимание, что отражение обычно немного медленное, и его следует использовать только тогда, когда вам это нужно (т. Е. При написании некоторого кода, который является динамическим и не может быть написан любым другим способом).

3 голосов
/ 07 ноября 2011

Вы, похоже, пытаетесь повторить синтаксис и семантику Haskell в F #. Не делай этого. Посмотрите на существующий код ML и узнайте, как решить вашу проблему идиоматически. Другими словами, ваш вопрос - проблема XY: вы задаете не тот вопрос.

Не зная, какую проблему вы пытаетесь решить, трудно ответить на ваш вопрос, но мое лучшее предположение:

type Expr = 
  | Prop of string
  | Conj of Expr * Expr
  | Disj of Expr * Expr
  | Impl of Expr * Expr

let deConj = function
  | Conj(a, b) -> a, b
  | _ -> invalidArg "expr" "deConj"

Возможно, вы хотите написать map поверх вашего expr типа:

let rec map f = function
  | Prop _ as t -> f t
  | Conj(a, b) -> f(Conj(map f a, map f b))
  | Disj(a, b) -> f(Disj(map f a, map f b))
  | Impl(a, b) -> f(Impl(map f a, map f b))

Другое решение - переписать ваш тип, чтобы исключить операторы:

type binOp = Conj | Disj | Impl
type expr =
  | Prop of string
  | BinOp of binOp * expr * expr

let rec map f = function
  | Prop _ as t -> f t
  | BinOp(op, a, b) -> f(BinOp(op, map f a, map f b))

EDIT

Я не уверен, что должна делать ваша buildtree функция, но если она вычисляет выражения, то, возможно, вам нужно что-то вроде этого:

let buildtree vars expr =
  map (function Proj v -> Map.find v vars | expr -> expr) expr

Это отобразит одно выражение в другое, заменив Proj v на соответствующее выражение (то есть значение переменной v), заданное vars.

3 голосов
/ 07 ноября 2011

Кортеж определяется как (exp1, exp2, ..., expn), например (1, «2», «3»). Я не вижу этот шаблон в вашем коде.

Если вы используете (exp1 exp2), это означает применение функции (примените exp2 в качестве первого аргумента к функции exp1). Ошибка, которую вы видите в своем коде, заключается в том, что вы определили Conj как функцию, принимающую функцию в качестве первого параметра, и передали строку («a») вместо функции.

Если ваш вопрос состоит в том, как разделить кортеж по голове и хвосту, вы можете использовать динамический подход, который только что объяснил Томас, он будет работать для любого n-кортежа, но вы потеряете информацию о типе.

В противном случае решение для сильного типа просто основано на сопоставлении с образцом:

let splitTuple (a,b,c) = (a,(b,c))
// Usage
let (head,tail) = splitTuple (1,"2",'3')

И если вы хотите, чтобы это работало для n-кортежей, вам нужно определить одну перегрузку для каждого n:

type TupleSplitter =
  static member splitTuple (a,b,c) = (a,(b,c))
  static member splitTuple (a,b,c,d) = (a,(b,c,d))
  static member splitTuple (a,b,c,d,e) = (a,(b,c,d,e))
// ... more overloads, as much as you need

// Usage
let (head,tail) = TupleSplitter.splitTuple (1,"2",'3',4.0)
// val tail : string * char * float = ("2", '3', 4.0)
// val head : int = 1
...