I've got the following F# code:
//Array iter version
let toSecureString (s:string) =
let sString = new SecureString()
s |> Array.iter (fun cl -> sString.AppendChar cl)
sString
I'm trying to convert a .Net string to a .Net SecureString. When I try to compile I get a Type Mismatch error:
stdin(60,10): error FS0001: Type mismatch. Expecting a
string -> 'a
but given a
'b [] -> unit
The type 'string' does not match the type ''a []'
If I don't specify the type of s, this is the type signature I see:
val toSecureString : char [] -> SecureString
But since I don't want to have to manually create an array of chars for the argument each time, it seems like I am missing something. How can I make this code work with a string parameter being passed in?
If it makes a difference I'm testing on F# 2.0 (Build 4.0.40219.1).
Any hints welcome. If this has already been asked and answered, post a link in the comments and I'll close this question.
Use Seq.iter, not Array.iter, because strings are char seqs but not char[]s.
To manipulate a string as a char seq, one can use String module. This works:
let toSecureString s =
let sString = new SecureString()
String.iter sString.AppendChar s
sString
You can also do this:
SecureString(&&s.ToCharArray().[0], s.Length)
Related
The TypeScript team has been doing great work on string literal typing in recent updates (4.1 & 4.2). I am wondering if there is a way to type a fixed length string.
Ex.
type LambdaServicePrefix = 'my-application-service';
type LambdaFunctionIdentifier = 'dark-matter-upgrader';
type LambdaFunctionName = `${LambdaServicePrefix}-${LambdaFunctionIdentifier}`; // error: longer than 32 characters...
How I imagine it would go is something like, Array<64, string>;. TypeScript has the Tuple type so as an array I could fix length of an array. [string, ... string * 62, string].
type FutureLambdaIdType = `${LambdaServicePrefix}-${string[32]}`;
UPDATED to reflect better recursive conditional type support
There are still, as of TS 4.7, no regular-expression-validated string types in TypeScript. Template literal types handle some, but not all, of the use cases for such regex types. If you have a situation like this where template literal types are insufficient, you might want to go to microsoft/TypeScript#41160 and describe your use case. The idea of a "string whose maximum length is N characters" for some N extends number would be easy enough to express with regex types, but is not easily achievable with template literals.
Still, let's see how close we can get.
A major roadblock stands in the way. TypeScript cannot easily represent the set of all strings less than N characters as a specific type StringsOfLengthUpTo<N>. Conceptually any given StringsOfLengthUpTo<N> is a large union, but since the compiler balks at unions with more than ~10,000 members, you can only describe strings of up to a few characters this way. Assuming you want to support the 95 characters of 7-bit printable ASCII, you will be able to represent StringsOfLengthUpTo<0>, StringsOfLengthUpTo<1>, and even StringsOfLengthUpTo<2>. But StringsOfLengthUpTo<3> would exceed the compiler's capacity, since it would be a union of over 800,000 members. So we have to give up on specific types.
Instead we can think of our type as a constraint used with generics. We need a type like TruncateTo<T, N> which takes a type T extends string and an N extends number and returns T truncated to N characters. Then we can constrain T extends TruncateTo<T, N> and the compiler would automatically warn on too-long strings.
It used to be that shallow recursion limits would prevent us from writing TruncateTo<T, N> for N greater than about 20 or so, but TypeScript 4.5 introduced support for tail recursion elimination on conditional types. That means we can write TruncateTo<T, N> by adding some extra accumulator arguments like this:
type TruncateTo<T extends string, N extends number,
L extends any[] = [], A extends string = ""> =
N extends L['length'] ? A :
T extends `${infer F}${infer R}` ? (
TruncateTo<R, N, [0, ...L], `${A}${F}`>
) :
A
This works by having an A accumulator to store the string we're building up, and an L arraylike accumulator that keeps track of how long that A string is (string literal types don't have a strongly typed length property, see ms/TS#34692 for the relevant request). We build up A one character at a time until we either run out of the original string, or until we reach a length of N. Let's see it in action:
type Fifteen = TruncateTo<"12345678901234567890", 15>;
// type Fifteen = "123456789012345"
type TwentyFive = TruncateTo<"123456789012345678901234567", 25>;
// type TwentyFive = "1234567890123456789012345"
We can't directly write T extends TruncateTo<T, N> as TypeScript complains that this is a circular constraint. But we can at least write a helper function like this:
const atMostN = <T extends string, N extends number>(
num: N, str: T extends TruncateTo<T, N> ? T : TruncateTo<T, N>
) => str;
and then you could call atMostN(32, "someStringLiteral") and it would either succeed or warn based on the the length of the string literal argument. Note that the str input is of a weird conditional type, whose sole purpose is to avoid the circular constraint. T is inferred from str, and then checked against TruncateTo<T, N>. If it succeeds, great. Otherwise, we give str the type of TruncateTo<T, N>, and we'll see an error message. It works like this:
const okay = atMostN(32, "ThisStringIs28CharactersLong"); // okay
type Okay = typeof okay; // "ThisStringIs28CharactersLong"
const bad = atMostN(32, "ThisStringHasALengthOf34Characters"); // error!
// -------------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// '"ThisStringHasALengthOf34Characters"' is not assignable to parameter of type
// '"ThisStringHasALengthOf34Characte"'.
type Bad = typeof bad; // "ThisStringHasALengthOf34Characte"
Is it worth it? Maybe. The original answer here had to do some unsavory things to get even a fixed-length check. The current one isn't so bad, but it's still a bunch of effort to get a compile-time check. So you might still have a use case for regex-validated string types.
Playground link to code
There is no way to represent fixed-length strings with Typescript. There is a very upvoted proposal here, but still this feature has not been released.
If the length is very little, there are some workarounds suchs as the following:
type Char = 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'
type String3 = `${Char}${Char}${Char}`
const a: String3 = 'aa' // error
const b: String3 = 'bbbbb' // error
const c: String3 = 'ccc' // OK
const d: String3 = 'abc' // OK
But you can't handle big lengths since you will run into a "Expression produces a union type that is too complex to represent" error.
It is impossible to limit the length of string by typing or typescript utils.
You can, however, use regex to validate the string (including length):
/^([a-zA-Z0-9_-]){1,64}$/
type IsThirteen<T extends number> = 13 extends T ? true : never
type IsFifteen<T extends number> = 15 extends T ? true : never
type LengthOfString<S extends string, T extends string[] = []> = S extends `${string}${infer R}`
? LengthOfString<R, [...T, string]>
: T['length'];
type IsLengthThirteenOrFifteen<T extends string> = true extends IsThirteen<LengthOfString<T>>
? T
: true extends IsFifteen<LengthOfString<T>>
? T
: never
function IsLengthThirteenOrFifteenGuard <T extends string>(a: IsLengthThirteenOrFifteen<T>) {
return a;
}
const b = IsLengthThirteenOrFifteenGuard('1131111111111')
Sources:
StringOfLength
Playground
I'm trying to write my first Swift program, and I know this question has been asked before, but the answers using split aren't working for me. I'm using Xcode 6.4 and Swift 1.2.
I have a String named line.
If I write
let inputs = split(line) {$0 = " "}
as suggested at Swift: Split a String into an array, I get the error message "Cannot invoke 'split' with an argument list of type (String, ()->)"
If I write
let inputs = split(line, {find(" ",$0) != nil}, allowEmptySlices: false)
as suggested at split now complains about missing "isSeparator", I get the error message, "Missing argument for parameter 'isSeparator' in call."
If I jump to the definition of split, I find
func split<S : Sliceable, R : BooleanType>(elements: S, maxSplit: Int = default, allowEmptySlices: Bool = default, #isSeparator: #noescape (S.Generator.Element) -> R) -> [S.SubSlice]
I don't understand what the type of the last parameter is, which is perhaps the root of my problem. Can you tell me how I should call split, and even better can you explain what the parameter type is? Why isn't the type simply (S)->R? I am getting the line from a generator that reads a file line-by-line, if that makes any difference.
for line:String in reader! {
let inputs = split(line) {$0 = " "}
...
}
As said in the comments to the question, the correct way is to use the == operator instead of =.
The type (S.Generator.Element) -> R) must be interpreted in the light of the definition of split:
func split<S : Sliceable, R : BooleanType>
(elements: S,
maxSplit: Int = default,
allowEmptySlices: Bool = default,
#isSeparator: #noescape (S.Generator.Element) -> R)
-> [S.SubSlice]
The type of split is a generic one: in other words, it is a function that can take as first parameter any value that satisfy a generic type (or protocol) subtype of Sliceable, like String, and return a result which must be a subtype of BooleanType (for instance true or false, which are instances of Bool). So the last parameter is a function which gets as parameter a type which is Element of Generator of S (for instance Character) and returns a value of type R. And {$0 == " "} is exactly a predicate of this type, that has an (implicit) parameter ($0), and check if it is equal to the character " ".
I tried to make a function in Idris like so:
strSplit : String -> Maybe (Char, String)
This would 'un-cons' the string into its first Char and the rest of the string, and return Nothing if it were empty.
So I wrote this, which failed:
strSplit x = case strM of
StrNil => Nothing
StrCons c cd => Just (c, cs)
So I then tried this, a bit like in Prelude.Strings:
strSplit x with (strM x)
strSplit "" | StrNil = Nothing
strSplit (strCons c cs) | (StrCons c cs) = Just (c, cs)
Which compiled and ran with no problems.
My question is, why do I have to use that with rule to split a string in this way, and why does my original method fail?
Note: Sorry, I can't access an interpreter at the moment, so I can't write the error message here yet.
There are two problems here. Firstly, in the 'case' block, the argument is strM rather than strM x as it is in the 'with' block, so you're inspecting different things.
There's a more interesting problem though, which is that if you try fixing the first one:
strSplit : String -> Maybe (Char, String)
strSplit x = case strM x of
StrNil => Nothing
StrCons c cd => Just (c, cs)
You'll get a different error (this is from current master which has reworded error messages):
Type mismatch between
StrM "" (Type of StrNil)
and
StrM x (Expected type)
So the distinction between 'case' and 'with' is that 'with' takes into account that the thing you're inspecting may influence the types and values on the left hand side. In the 'case', matching strM x means that x must be "", but a 'case' can appear anywhere and takes no account of the effect on the types of the other arguments (working out appropriate type checking rules for this would be quite a challenge...).
On the other hand, 'with' can only appear at the top level: effectively what it's doing is adding another top level thing to match on which, being top level, can affect the types and values of the other patterns.
So, the short answer is that 'with' supports dependent pattern matching, but 'case' does not.
I have a question I am rather unsure about.
My questions is as follows
let myFunc (text:string) (times:int) = ....
What I want this function to do is put the string together as many times as specified by the times parameter.
if input = "check " 3 I want the output string = "check check check"
I have tried with a loop, but couldn't seem to make it work.
Anyone?
Actually the function is already in String module:
let multiply text times = String.replicate times text
To write your own function, an efficient way is using StringBuilder:
open System.Text
let multiply (text: string) times =
let sb = new StringBuilder()
for i in 1..times do
sb.Append(text) |> ignore
sb.ToString()
If you want to remove trailing whitespaces as in your example, you can use Trim() member in String class to do so.
A variation on pad's solution, given that it's just a fold:
let multiply n (text: string) =
(StringBuilder(), {1..n})
||> Seq.fold(fun b _ -> b.Append(text))
|> sprintf "%O"
If you want a pure functional "do-it-yourself" version for F# learning purposes, then something like the following snippet will do:
let myFunc times text =
let rec grow result doMore =
if doMore > 0 then
grow (result + text) (doMore- 1)
else
result
grow "" times
Here is the test:
> myFunc 3 "test";;
val it : string = "testtesttest"
Otherwise you should follow the pointer about the standard F# library function replicate given in pad's answer.
String.replicate already provides the functionality you're looking for.
If for some reason you want the arguments reversed, you can do it as follows:
(* A general function you should add to your utilities *)
let flip f a b = f b a
let myFunc = flip String.replicate
In a simple recursive fashion:
let rec dupn = function
|s,1 -> s
|s,n -> s ^ dupn(s, n-1)
Theres is a little problem I want to solve with Haskell:
let substitute a function that change all of the wildcards in a string for one concrete parameter. The function has de signature of:
subs :: String -> String -> String -> String
-- example:
-- subs 'x' "x^3 + x + sin(x)" "6.2" will generate
-- "6.2^3 + 6.2 + sin(6.2)"
You could use the Text.Regex package.
Your example might look something like this:
import Text.Regex(mkRegex, subRegex)
subs :: String -> String -> String -> String
subs wildcard input value = subRegex (mkRegex wildcard) input value
See http://bluebones.net/2007/01/replace-in-haskell/ for an example which looks exactly as the piece of code you are looking for.
You can use text-format-simple library for such cases:
import Text.Format
format "{0}^3 + {0} + sin({0})" ["6.2"]
Use regular expressions (Text.Regex.Posix) and search-replace for /\Wx\W/ (Perl notation). Simply replacing x to 6.2 will bring you trouble with x + quux.
Haskell Regex Replace for more information (I think this should be imported to SO.
For extra hard-core you could parse your expression as AST and do the replacement on that level.