68

F#/機能スニペットについては、既に2 つの 質問があります。

ただし、ここで探しているのは、便利なスニペット、つまり再利用可能な小さな「ヘルパー」関数です。または、まったく覚えていない、あいまいだが気の利いたパターン。

何かのようなもの:

open System.IO

let rec visitor dir filter= 
    seq { yield! Directory.GetFiles(dir, filter)
          for subdir in Directory.GetDirectories(dir) do 
              yield! visitor subdir filter} 

便利なリファレンスページのようなものにしたいと思います。そのため、正しい答えはありませんが、多くの良い答えがあることを願っています.

EDIT Tomas Petricek は、F# スニペット専用のサイトhttp://fssnip.net/を作成しました。

4

31 に答える 31

28

中置演算子

これはhttp://sandersn.com/blog//index.php/2009/10/22/infix-function-trick-for-fから入手しました。詳細については、そのページにアクセスしてください。

Haskellをご存知の場合は、F#でインフィックスシュガーが不足していることに気付くかもしれません。

// standard Haskell call has function first, then args just like F#. So obviously
// here there is a function that takes two strings: string -> string -> string 
startsWith "kevin" "k"

//Haskell infix operator via backQuotes. Sometimes makes a function read better.
"kevin" `startsWith` "K" 

F#には真の「中置」演算子はありませんが、パイプラインと「バックパイプライン」(誰がそのようなことを知っていたのですか??)を介して、ほぼ同じようにエレガントに実行できます。

// F# 'infix' trick via pipelines
"kevin" |> startsWith <| "K"
于 2010-09-22T00:44:33.070 に答える
28

Perl スタイルの正規表現マッチング

let (=~) input pattern =
    System.Text.RegularExpressions.Regex.IsMatch(input, pattern)

let test = "monkey" =~ "monk.+"表記法を使用してテキストを一致させることができます。

于 2009-09-25T13:07:09.167 に答える
27

複数行の文字列

これはかなり些細なことですが、あまり知られていない F# 文字列の機能のようです。

let sql = "select a,b,c \
           from table \
           where a = 1"

これにより、次が生成されます。

val sql : string = "select a,b,c from table where a = 1"

F# コンパイラは、文字列リテラル内でバックスラッシュの後にキャリッジ リターンが続くのを検出すると、バックスラッシュから次の行の最初の非スペース文字までのすべてを削除します。これにより、一連の文字列連結を使用せずに、複数行の文字列リテラルを並べることができます。

于 2010-09-24T16:40:00.727 に答える
25

本人による一般的メモ化

let memoize f = 
  let cache = System.Collections.Generic.Dictionary<_,_>(HashIdentity.Structural)
  fun x ->
    let ok, res = cache.TryGetValue(x)
    if ok then res
    else let res = f x
         cache.[x] <- res
         res

これを使用すると、キャッシュされたリーダーを次のように実行できます。

let cachedReader = memoize reader
于 2009-05-12T06:40:30.533 に答える
19

テキストファイルへの単純な読み書き

これらは些細なことですが、ファイル アクセスをパイプ可能にします。

open System.IO
let fileread f = File.ReadAllText(f)
let filewrite f s = File.WriteAllText(f, s)
let filereadlines f = File.ReadAllLines(f)
let filewritelines f ar = File.WriteAllLines(f, ar)

そう

let replace f (r:string) (s:string) = s.Replace(f, r)

"C:\\Test.txt" |>
    fileread |>
    replace "teh" "the" |>
    filewrite "C:\\Test.txt"

そして、それを質問で引用された訪問者と組み合わせる:

let filereplace find repl path = 
    path |> fileread |> replace find repl |> filewrite path

let recurseReplace root filter find repl = 
    visitor root filter |> Seq.iter (filereplace find repl)

「ロックされた」ファイル (Excel で既に開いている csv ファイルなど) を読み取れるようにする場合は、わずかな改善を更新します。

let safereadall f = 
   use fs = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
   use sr = new StreamReader(fs, System.Text.Encoding.Default)
   sr.ReadToEnd()

let split sep (s:string) = System.Text.RegularExpressions.Regex.Split(s, sep)

let fileread f = safereadall f
let filereadlines f = f |> safereadall |> split System.Environment.NewLine  
于 2009-05-07T08:58:58.050 に答える
18

null をチェックする必要があるパフォーマンス集約型の場合

let inline isNull o = System.Object.ReferenceEquals(o, null)
if isNull o then ... else ...

約20倍高速です

if o = null then ... else ...
于 2010-10-13T21:29:29.260 に答える
11

Active Patterns、別名「Banana Splits」は、1 つのパターンを複数の正規表現パターンに一致させる非常に便利な構造です。これはAWKによく似ていますが、成功するまでパターンが順番に照合されるため、DFAの高いパフォーマンスはありません。

#light
open System
open System.Text.RegularExpressions

let (|Test|_|) pat s =
    if (new Regex(pat)).IsMatch(s)
    then Some()
    else None

let (|Match|_|) pat s =
    let opt = RegexOptions.None
    let re = new Regex(pat,opt)
    let m = re.Match(s)
    if m.Success
    then Some(m.Groups)
    else None

使用例:

let HasIndefiniteArticle = function
        | Test "(?: |^)(a|an)(?: |$)" _ -> true
        | _ -> false

type Ast =
    | IntVal of string * int
    | StringVal of string * string
    | LineNo of int
    | Goto of int

let Parse = function
    | Match "^LET\s+([A-Z])\s*=\s*(\d+)$" g ->
        IntVal( g.[1].Value, Int32.Parse(g.[2].Value) )
    | Match "^LET\s+([A-Z]\$)\s*=\s*(.*)$" g ->
        StringVal( g.[1].Value, g.[2].Value )
    | Match "^(\d+)\s*:$" g ->
        LineNo( Int32.Parse(g.[1].Value) )
    | Match "^GOTO \s*(\d+)$" g ->
        Goto( Int32.Parse(g.[1].Value) )
    | s -> failwithf "Unexpected statement: %s" s
于 2009-05-08T16:03:55.970 に答える
8

多分モナド

type maybeBuilder() =
    member this.Bind(v, f) =
        match v with
        | None -> None
        | Some(x) -> f x
    member this.Delay(f) = f()
    member this.Return(v) = Some v

let maybe = maybeBuilder()

ここでは、初心者向けにモナドについて簡単に紹介します。

于 2009-09-25T13:14:26.050 に答える
8

FloatWithMeasure関数http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx を使用して、単位を処理しない関数を「ユニット化」します

let unitize (f:float -> float) (v:float<'u>) =
  LanguagePrimitives.FloatWithMeasure<'u> (f (float v))

例:

[<Measure>] type m
[<Measure>] type kg

let unitize (f:float -> float) (v:float<'u>) =
  LanguagePrimitives.FloatWithMeasure<'u> (f (float v))

//this function doesn't take units
let badinc a = a + 1.

//this one does!
let goodinc v = unitize badinc v

goodinc 3.<m>
goodinc 3.<kg>

古いバージョン:

let unitize (f:float -> float) (v:float<'u>) =
  let unit = box 1. :?> float<'u>
  unit * (f (v/unit))

kvbへの称賛

于 2009-09-11T20:21:42.003 に答える
8

オプション合体演算子

defaultArgC# の null 合体演算子に近い構文を持つ関数のバージョンが必要でした??。これにより、非常に簡潔な構文を使用して、デフォルト値を提供しながら Option から値を取得できます。

/// Option-coalescing operator - this is like the C# ?? operator, but works with 
/// the Option type.
/// Warning: Unlike the C# ?? operator, the second parameter will always be 
/// evaluated.
/// Example: let foo = someOption |? default
let inline (|?) value defaultValue =
    defaultArg value defaultValue

/// Option-coalescing operator with delayed evaluation. The other version of 
/// this operator always evaluates the default value expression. If you only 
/// want to create the default value when needed, use this operator and pass
/// in a function that creates the default.
/// Example: let foo = someOption |?! (fun () -> new Default())
let inline (|?!) value f =
    match value with Some x -> x | None -> f()
于 2010-09-15T18:21:33.623 に答える
7

スケール/比率関数ビルダー

繰り返しますが、些細なことですが、便利です。

//returns a function which will convert from a1-a2 range to b1-b2 range
let scale (a1:float<'u>, a2:float<'u>) (b1:float<'v>,b2:float<'v>) = 
    let m = (b2 - b1)/(a2 - a1) //gradient of line (evaluated once only..)
    (fun a -> b1 + m * (a - a1))

例:

[<Measure>] type m
[<Measure>] type px

let screenSize = (0.<px>, 300.<px>)
let displayRange = (100.<m>, 200.<m>)
let scaleToScreen = scale displayRange screenSize

scaleToScreen 120.<m> //-> 60.<px>
于 2010-09-07T09:13:38.357 に答える
6

リストの転置( Jomo Fisher のブログで参照)

///Given list of 'rows', returns list of 'columns' 
let rec transpose lst =
    match lst with
    | (_::_)::_ -> List.map List.head lst :: transpose (List.map List.tail lst)
    | _         -> []

transpose [[1;2;3];[4;5;6];[7;8;9]] // returns [[1;4;7];[2;5;8];[3;6;9]]

そして、これは(私の大ざっぱなプロファイリングから)やや遅いですが、内部リストが(私のマシンで)10000要素より長い場合にスタックオーバーフローをスローしないという利点があります:

let transposeTR lst =
  let rec inner acc lst = 
    match lst with
    | (_::_)::_ -> inner (List.map List.head lst :: acc) (List.map List.tail lst)
    | _         -> List.rev acc
  inner [] lst

私が賢いなら、非同期で並列化してみます...

于 2009-05-07T09:10:24.933 に答える
6

F# マップ <-> C# 辞書

(私は知っています、私は知っています、System.Collections.Generic.Dictionary は実際には 'C#' 辞書ではありません)

C# から F#

(dic :> seq<_>)                        //cast to seq of KeyValuePair
    |> Seq.map (|KeyValue|)            //convert KeyValuePairs to tuples
    |> Map.ofSeq                       //convert to Map

(Brian から、ここに、以下のコメントで Mauricio によって改善が提案されています。(|KeyValue|)は、KeyValuePair に一致するためのアクティブなパターンです - FSharp.Core から - に相当し(fun kvp -> kvp.Key, kvp.Value)ます)

興味深い代替案

すべての不変の利点を取得するには、Dictionary の O(1) 検索速度を使用してdict、不変の IDictionary を返す演算子を使用できます (この質問を参照してください)。

現在、このメソッドを使用して Dictionary を直接変換する方法はわかりません。

(dic :> seq<_>)                        //cast to seq of KeyValuePair
    |> (fun kvp -> kvp.Key, kvp.Value) //convert KeyValuePairs to tuples
    |> dict                            //convert to immutable IDictionary

F# から C#

let dic = Dictionary()
map |> Map.iter (fun k t -> dic.Add(k, t))
dic

ここで奇妙なのは、FSI が型を (たとえば) 次のように報告することです。

val it : Dictionary<string,int> = dict [("a",1);("b",2)]

しかし、あなたがフィードバックすればdict [("a",1);("b",2)]、FSIは報告します

IDictionary<string,int> = seq[[a,1] {Key = "a"; Value = 1; } ...
于 2010-03-17T06:36:27.877 に答える
5

LINQ-to-XML ヘルパー

namespace System.Xml.Linq

// hide warning about op_Explicit
#nowarn "77"

[<AutoOpen>]
module XmlUtils =

    /// Converts a string to an XName.
    let xn = XName.op_Implicit
    /// Converts a string to an XNamespace.
    let xmlns = XNamespace.op_Implicit

    /// Gets the string value of any XObject subclass that has a Value property.
    let inline xstr (x : ^a when ^a :> XObject) =
        (^a : (member get_Value : unit -> string) x)

    /// Gets a strongly-typed value from any XObject subclass, provided that
    /// an explicit conversion to the output type has been defined.
    /// (Many explicit conversions are defined on XElement and XAttribute)
    /// Example: let value:int = xval foo
    let inline xval (x : ^a when ^a :> XObject) : ^b = 
        ((^a or ^b) : (static member op_Explicit : ^a -> ^b) x) 

    /// Dynamic lookup operator for getting an attribute value from an XElement.
    /// Returns a string option, set to None if the attribute was not present.
    /// Example: let value = foo?href
    /// Example with default: let value = defaultArg foo?Name "<Unknown>"
    let (?) (el:XElement) (name:string) =
        match el.Attribute(xn name) with
        | null -> None
        | att  -> Some(att.Value)

    /// Dynamic operator for setting an attribute on an XElement.
    /// Example: foo?href <- "http://www.foo.com/"
    let (?<-) (el:XElement) (name:string) (value:obj) =
        el.SetAttributeValue(xn name, value)
于 2010-09-15T18:10:42.073 に答える
4

配列の加重合計

[k-array] の重みに基づいて、数値の [k-array of n-arrays] の重み付けされた [n-array] の合計を計算する

この質問からコピー、およびkvb回答

これらの配列を考えると

let weights = [|0.6;0.3;0.1|]

let arrs = [| [|0.0453;0.065345;0.07566;1.562;356.6|] ; 
           [|0.0873;0.075565;0.07666;1.562222;3.66|] ; 
           [|0.06753;0.075675;0.04566;1.452;3.4556|] |]

配列の両方の次元が可変である可能性があるため、加重合計 (列ごと) が必要です。

Array.map2 (fun w -> Array.map ((*) w)) weights arrs 
|> Array.reduce (Array.map2 (+))

最初の行: 最初の Array.map2 関数を重みに部分的に適用すると、新しい関数 (Array.map ((*) weight) が生成され、arr.map の各配列に (重みごとに) 適用されます。

2 行目: Array.reduce は fold に似ていますが、2 番目の値から開始し、最初の値を初期の「状態」として使用する点が異なります。この場合、各値は配列の配列の「行」です。したがって、最初の 2 行に Array.map2 (+) を適用すると、最初の 2 つの配列が合計され、新しい配列が残り、それを (Array.reduce) 次の行 (この場合は最後) に再び合計することになります。配列。

結果:

[|0.060123; 0.069444; 0.07296; 1.5510666; 215.40356|]
于 2010-02-25T06:28:59.523 に答える
4

OK、これはスニペットとは関係ありませんが、私はこれを忘れ続けています:

インタラクティブ ウィンドウにいる場合は、F7を押してコード ウィンドウに戻ります (実行したばかりのコードの選択を解除する必要はありません...)。

コード ウィンドウから F# ウィンドウに移動する (および F# ウィンドウを開く) ことは、Ctrl Alt F

(CodeRush がバインディングを盗んでいない限り...)

于 2009-09-17T06:50:19.480 に答える
3

F# の DataSetExtensions、DataReaders

System.Data.DataSetExtensions.dllは、 System.Nullable をサポートすることにより適切に処理する方法で、 をDataTableとして扱うIEnumerable<DataRow>だけでなく、個々のセルの値をボックス化解除する機能を追加します。DBNullたとえば、C# では、null を含む整数列の値を取得DBNullし、非常に簡潔な構文でデフォルトをゼロにするように指定できます。

var total = myDataTable.AsEnumerable()
                       .Select(row => row.Field<int?>("MyColumn") ?? 0)
                       .Sum();

ただし、DataSetExtensions が不足している領域が 2 つあります。1 つ目はサポートしていないことIDataReader、2 つ目は F#option型をサポートしていないことです。次のコードは両方を実行します。IDataReaderを として扱うseq<IDataRecord>ことができ、F# オプションまたは System.Nullable をサポートして、リーダーまたはデータセットから値をボックス化解除できます。別の回答のオプション合体演算子と組み合わせると、DataReader を操作するときに次のようなコードが可能になります。

let total =
    myReader.AsSeq
    |> Seq.map (fun row -> row.Field<int option>("MyColumn") |? 0)
    |> Seq.sum

おそらく、データベースの null を無視するより慣用的な F# の方法は...

let total =
    myReader.AsSeq
    |> Seq.choose (fun row -> row.Field<int option>("MyColumn"))
    |> Seq.sum

さらに、以下に定義する拡張メソッドは、F# と C#/VB の両方から使用できます。

open System
open System.Data
open System.Reflection
open System.Runtime.CompilerServices
open Microsoft.FSharp.Collections

/// Ported from System.Data.DatasetExtensions.dll to add support for the Option type.
[<AbstractClass; Sealed>]
type private UnboxT<'a> private () =

    // This class generates a converter function based on the desired output type,
    // and then re-uses the converter function forever. Because the class itself is generic,
    // different output types get different cached converter functions.

    static let referenceField (value:obj) =
        if value = null || DBNull.Value.Equals(value) then
            Unchecked.defaultof<'a>
        else
            unbox value

    static let valueField (value:obj) =
        if value = null || DBNull.Value.Equals(value) then
            raise <| InvalidCastException("Null cannot be converted to " + typeof<'a>.Name)
        else
            unbox value

    static let makeConverter (target:Type) methodName =
        Delegate.CreateDelegate(typeof<Converter<obj,'a>>,
                                typeof<UnboxT<'a>>
                                    .GetMethod(methodName, BindingFlags.NonPublic ||| BindingFlags.Static)
                                    .MakeGenericMethod([| target.GetGenericArguments().[0] |]))
        |> unbox<Converter<obj,'a>>
        |> FSharpFunc.FromConverter

    static let unboxFn =
        let theType = typeof<'a>
        if theType.IsGenericType && not theType.IsGenericTypeDefinition then
            let genericType = theType.GetGenericTypeDefinition()
            if typedefof<Nullable<_>> = genericType then
                makeConverter theType "NullableField"
            elif typedefof<option<_>> = genericType then
                makeConverter theType "OptionField"
            else
                invalidOp "The only generic types supported are Option<T> and Nullable<T>."
        elif theType.IsValueType then
            valueField
        else
            referenceField

    static member private NullableField<'b when 'b : struct and 'b :> ValueType and 'b:(new:unit -> 'b)> (value:obj) =
        if value = null || DBNull.Value.Equals(value) then
            Nullable<_>()
        else
            Nullable<_>(unbox<'b> value)

    static member private OptionField<'b> (value:obj) =
        if value = null || DBNull.Value.Equals(value) then
            None
        else
            Some(unbox<'b> value)

    static member inline Unbox =
        unboxFn

/// F# data-related extension methods.
[<AutoOpen>]
module FsDataEx =

    type System.Data.IDataReader with

        /// Exposes a reader's current result set as seq<IDataRecord>.
        /// Reader is closed when sequence is fully enumerated.
        member this.AsSeq =
            seq { use reader = this
                  while reader.Read() do yield reader :> IDataRecord }

        /// Exposes all result sets in a reader as seq<seq<IDataRecord>>.
        /// Reader is closed when sequence is fully enumerated.
        member this.AsMultiSeq =
            let rowSeq (reader:IDataReader)  =
                seq { while reader.Read() do yield reader :> IDataRecord }
            seq {
                use reader = this
                yield rowSeq reader
                while reader.NextResult() do
                    yield rowSeq reader
            }

        /// Populates a new DataSet with the contents of the reader. Closes the reader after completion.
        member this.ToDataSet () =
            use reader = this
            let dataSet = new DataSet(RemotingFormat=SerializationFormat.Binary, EnforceConstraints=false)
            dataSet.Load(reader, LoadOption.OverwriteChanges, [| "" |])
            dataSet

    type System.Data.IDataRecord with

        /// Gets a value from the record by name. 
        /// DBNull and null are returned as the default value for the type.
        /// Supports both nullable and option types.
        member this.Field<'a> (fieldName:string) =
            this.[fieldName] |> UnboxT<'a>.Unbox

        /// Gets a value from the record by column index. 
        /// DBNull and null are returned as the default value for the type.
        /// Supports both nullable and option types.
        member this.Field<'a> (ordinal:int) =
            this.GetValue(ordinal) |> UnboxT<'a>.Unbox

    type System.Data.DataRow with

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (columnName:string) =
            this.[columnName] |> UnboxT<'a>.Unbox

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (columnIndex:int) =
            this.[columnIndex] |> UnboxT<'a>.Unbox

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (column:DataColumn) =
            this.[column] |> UnboxT<'a>.Unbox

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (columnName:string, version:DataRowVersion) =
            this.[columnName, version] |> UnboxT<'a>.Unbox

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (columnIndex:int, version:DataRowVersion) =
            this.[columnIndex, version] |> UnboxT<'a>.Unbox

        /// Identical to the Field method from DatasetExtensions, but supports the F# Option type.
        member this.Field2<'a> (column:DataColumn, version:DataRowVersion) =
            this.[column, version] |> UnboxT<'a>.Unbox


/// C# data-related extension methods.
[<Extension; AbstractClass; Sealed>]
type CsDataEx private () =

    /// Populates a new DataSet with the contents of the reader. Closes the reader after completion.
    [<Extension>]    
    static member ToDataSet(this:IDataReader) =
        this.ToDataSet()

    /// Exposes a reader's current result set as IEnumerable{IDataRecord}.
    /// Reader is closed when sequence is fully enumerated.
    [<Extension>]
    static member AsEnumerable(this:IDataReader) =
        this.AsSeq

    /// Exposes all result sets in a reader as IEnumerable{IEnumerable{IDataRecord}}.
    /// Reader is closed when sequence is fully enumerated.
    [<Extension>]
    static member AsMultipleEnumerable(this:IDataReader) =
        this.AsMultiSeq

    /// Gets a value from the record by name. 
    /// DBNull and null are returned as the default value for the type.
    /// Supports both nullable and option types.
    [<Extension>]
    static member Field<'T> (this:IDataRecord, fieldName:string) =
        this.Field<'T>(fieldName)

    /// Gets a value from the record by column index. 
    /// DBNull and null are returned as the default value for the type.
    /// Supports both nullable and option types.
    [<Extension>]
    static member Field<'T> (this:IDataRecord, ordinal:int) =
        this.Field<'T>(ordinal)
于 2010-09-15T18:46:40.457 に答える
2

XElementsの作成

驚くべきことは何もありませんが、XNamesの暗黙の変換に巻き込まれ続けています。

#r "System.Xml.Linq.dll"
open System.Xml.Linq

//No! ("type string not compatible with XName")
//let el = new XElement("MyElement", "text") 

//better
let xn s = XName.op_Implicit s
let el = new XElement(xn "MyElement", "text")

//or even
let xEl s o = new XElement(xn s, o)
let el = xEl "MyElement" "text"
于 2010-01-27T07:00:45.057 に答える
2

ペアワイズとペア

私は常に Seq.pairwise が [(1,2);(3;4)] ではなく [(1,2);(2,3);(3,4)] を返すことを期待しています。リストにはどちらも存在せず、両方が必要だったので、後で参照するためのコードを次に示します。それらは末尾再帰的だと思います。

//converts to 'windowed tuples' ([1;2;3;4;5] -> [(1,2);(2,3);(3,4);(4,5)])
let pairwise lst = 
    let rec loop prev rem acc = 
       match rem with
       | hd::tl -> loop hd tl ((prev,hd)::acc)
       | _ -> List.rev acc
    loop (List.head lst) (List.tail lst) []

//converts to 'paged tuples' ([1;2;3;4;5;6] -> [(1,2);(3,4);(5,6)])    
let pairs lst = 
    let rec loop rem acc = 
       match rem with
       | l::r::tl -> loop tl ((l,r)::acc)
       | l::[] -> failwith "odd-numbered list" 
       | _ -> List.rev acc
    loop lst []
于 2010-02-16T07:03:09.673 に答える
2

コマンド ライン アプリケーションでの引数の処理:

//We assume that the actual meat is already defined in function 
//    DoStuff (string -> string -> string -> unit)
let defaultOutOption = "N"
let defaultUsageOption = "Y"

let usage =  
      "Scans a folder for and outputs results.\n" +
      "Usage:\n\t MyApplication.exe FolderPath [IncludeSubfolders (Y/N) : default=" + 
      defaultUsageOption + "] [OutputToFile (Y/N): default=" + defaultOutOption + "]"

let HandlArgs arr = 
    match arr with
        | [|d;u;o|] -> DoStuff d u o
        | [|d;u|] -> DoStuff d u defaultOutOption 
        | [|d|] -> DoStuff d defaultUsageOption defaultOutOption 
        | _ ->  
            printf "%s" usage
            Console.ReadLine() |> ignore

[<EntryPoint>]
let main (args : string array) = 
    args |> HandlArgs
    0

(この手法はRobert Pickeringに触発されたという漠然とした記憶がありましたが、今は参考文献を見つけることができません)

于 2009-09-25T06:59:14.640 に答える
1

ナイーブなCSVリーダー(つまり、厄介なものは何も処理しません)

(ここで他の回答からfilereadlinesとList.transposeを使用)

///Given a file path, returns a List of row lists
let ReadCSV = 
        filereadlines
            >> Array.map ( fun line -> line.Split([|',';';'|]) |> List.ofArray )
            >> Array.toList

///takes list of col ids and list of rows, 
///   returns array of columns (in requested order)
let GetColumns cols rows = 
    //Create filter
    let pick cols (row:list<'a>) = List.map (fun i -> row.[i]) cols

    rows 
        |> transpose //change list of rows to list of columns
        |> pick cols      //pick out the columns we want
        |> Array.ofList  //an array output is easier to index for user

"C:\MySampleCSV"
   |> ReadCSV
   |> List.tail //skip header line
   |> GetColumns [0;3;1]  //reorder columns as well, if needs be.
于 2009-09-25T07:29:11.523 に答える
1

コードを SQL に切り替える

このリストのほとんどよりも些細なことですが、それでも便利です。

私は常に、開発中に SQL 環境に移動するために、SQL をコードに出し入れしています。例:

let sql = "select a,b,c "
    + "from table "
    + "where a = 1"

次のように「剥ぎ取る」必要があります。

select a,b,c
from table
where a = 1

フォーマットを維持します。SQL エディターのコード シンボルを取り除き、SQL を完成させたときに手動で元に戻すのは面倒です。これらの 2 つの関数は、SQL をコードからストリップに切り替えます。

// reads the file with the code quoted sql, strips code symbols, dumps to FSI
let stripForSql fileName = 
    File.ReadAllText(fileName)
    |> (fun s -> Regex.Replace(s, "\+(\s*)\"", "")) 
    |> (fun s -> s.Replace("\"", ""))
    |> (fun s -> Regex.Replace(s, ";$", "")) // end of line semicolons
    |> (fun s -> Regex.Replace(s, "//.+", "")) // get rid of any comments
    |> (fun s -> printfn "%s" s)

コード ソース ファイルに戻す準備ができたら、次のようにします。

let prepFromSql fileName = 
    File.ReadAllText(fileName)
    |> (fun s -> Regex.Replace(s, @"\r\n", " \"\r\n+\"")) // matches newline 
    |> (fun s -> Regex.Replace(s, @"\A", " \"")) 
    |> (fun s -> Regex.Replace(s, @"\z", " \"")) 
    |> (fun s -> printfn "%s" s)

入力ファイルを削除したいのですが、それを実現する方法を理解することさえできません。誰でも?

編集:

Windowsフォームダイアログの入力/出力を追加することで、これらの機能のファイルの要件を排除する方法を見つけました。表示するにはコードが多すぎますが、そのようなことをしたい人のために、それが私が解決した方法です。

于 2010-09-24T01:20:39.240 に答える
1

パスカルの三角形 (ねえ、誰かが役に立つと思うかもしれません)

したがって、次のようなものを作成したいと思います。

       1
      1 1
     1 2 1
    1 3 3 1
   1 4 6 4 1

簡単です:

let rec next = function
    | [] -> []
    | x::y::xs -> (x + y)::next (y::xs)
    | x::xs -> x::next xs

let pascal n =
    seq { 1 .. n }
    |> List.scan (fun acc _ -> next (0::acc) ) [1]

このnext関数は、各 item[i] = item[i] + item[i + 1] である新しいリストを返します。

fsi の出力は次のとおりです。

> pascal 10 |> Seq.iter (printfn "%A");;
[1]
[1; 1]
[1; 2; 1]
[1; 3; 3; 1]
[1; 4; 6; 4; 1]
[1; 5; 10; 10; 5; 1]
[1; 6; 15; 20; 15; 6; 1]
[1; 7; 21; 35; 35; 21; 7; 1]
[1; 8; 28; 56; 70; 56; 28; 8; 1]
[1; 9; 36; 84; 126; 126; 84; 36; 9; 1]
[1; 10; 45; 120; 210; 252; 210; 120; 45; 10; 1]

冒険好きな方のために、末尾再帰バージョンを次に示します。

let rec next2 cont = function
    | [] -> cont []
    | x::y::xs -> next2 (fun l -> cont <| (x + y)::l ) <| y::xs
    | x::xs -> next2 (fun l -> cont <| x::l ) <| xs

let pascal2 n =
    set { 1 .. n }
    |> Seq.scan (fun acc _ -> next2 id <| 0::acc)) [1]
于 2009-11-19T18:27:28.507 に答える
1

日付範囲

fromDateとの間の日付のシンプルだが便利なリストtoDate

let getDateRange  fromDate toDate  =

    let rec dates (fromDate:System.DateTime) (toDate:System.DateTime) = 
        seq {
            if fromDate <= toDate then 
                yield fromDate
                yield! dates (fromDate.AddDays(1.0)) toDate
            }

    dates fromDate toDate
    |> List.ofSeq
于 2010-09-21T21:56:39.087 に答える
0

float のリスト内包表記

これ[23.0 .. 1.0 .. 40.0]は、サポートされているいくつかのバージョンで非推奨としてマークされました。

しかし、どうやら、これはうまくいきます:

let dl = 9.5 / 11.
let min = 21.5 + dl
let max = 40.5 - dl

let a = [ for z in min .. dl .. max -> z ]
let b = a.Length

(ところで、そこには浮動小数点の問題があります。fssnipで発見- F# スニペットの別の場所)

于 2011-03-25T08:05:59.690 に答える
0

リストを平坦化する

このようなものがある場合:

let listList = [[1;2;3;];[4;5;6]] 

それを単一のリストに「フラット化」したいので、結果は次のようになります。

[1;2;3;4;5;6]

それは次のように行うことができます:

let flatten (l: 'a list list) =
    seq {
            yield List.head (List.head l) 
            for a in l do yield! (Seq.skip 1 a) 
        } 

    |> List.ofSeq
于 2010-10-12T20:21:19.733 に答える
-2

レコードをnullに設定する

type Foo = { x : int }
let inline retype (x:'a) : 'b = (# "" x : 'b #)
let f : Foo = retype null
于 2010-10-13T21:30:45.793 に答える
-2

パラレルマップ

let pmap f s =
    seq { for a in s -> async { return f s } }
    |> Async.Parallel
    |> Async.Run
于 2009-09-25T13:08:25.593 に答える