Why is foldl signature is a pipeline instead of a tuple like type in SML? - smlnj

I do not understand why the signature of foldl is like that.
Standard ML of New Jersey v110.79 [built: Tue Aug 8 23:21:20 2017]
- foldl;
val it = fn : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
In particular, the arrows -> should've been asterisk * like the following:
val it = fn : ('a * 'b -> 'b) * 'b * 'a list -> 'b
And the reason is because foldl takes the following:
Function ('a * 'b -> 'b) that compares & returns one of two strings; assuming acc is 'b, thus, returning acc
acc & 'a list to compare them.
Finally, returning the base 'b which is acc.

* entails it to be a tuple, and which necessitates that all the components of the tuple will have to be provided... -> entails currying, which allows partial application. Both are 2 different semantics.
Also, it is interesting that you write
...foldl takes a function that compares two strings....
foldl is generic and quite polymorphic, so why will it work only with string. A particular function application may work over string data, but not the function definition itself.

Related

SML - Passing NONE or SOME as argument

I have just started on SML and I am having trouble trying to pass NONE/SOME as parameters to a function.
fun fx (SOME x) (SOME y) f = f x y
| fx (SOME x) (NONE) f = NONE
| fx (NONE) (SOME y) f = NONE
| fx (NONE) (NONE) f = NONE;
fun add x y = x + y;
fx (SOME 2) (SOME 4) add;
What I am trying to do is to add two numbers only if neither values are NONE. But I get the following error:
Error: operator and operand do not agree [tycon mismatch]
operator domain: int -> int -> 'Z option
operand: int -> int -> int
in expression:
((fx (SOME 2)) (SOME 4)) add
If remove the cases for NONE, i.e:
fun fx (SOME x) (SOME y) f = f x y
Then it works alright. I don't know where exactly am I making a mistake. f parameter is not optional, yet it is treating as one.
You've already answered the "how", so I will try and explain the "why".
Look at the type of fx in the REPL:
val fx = fn : 'a option -> 'b option -> ('a -> 'b -> 'c option) -> 'c option
It produces a 'c option (it is known from your NONE cases that the result is an option type).
(Note that 'a -> 'b -> 'c option is 'a -> ('b -> ('c option)), not ('a -> 'b -> 'c) option.)
Since your first case is f x y, that must produce an option type - and add doesn't.
This is what the error message is trying to say; since SOME 2 and SOME 4 are int options, fx (SOME 2) (SOME 4) has the type (int -> int -> int option) -> int option (the "operator domain" is int -> int -> int option), but add is an int -> int -> int.
(The use of the word "operator" here is a bit confusing. You get used to it.)
If you want the more generic type 'a option -> 'b option -> ('a -> 'b -> 'c) -> 'c option, you need to wrap the result (as you've found):
fun fx (SOME x) (SOME y) f = SOME (f x y)
Like Nalin pointed out in the comments, I had to redefine the method, just not on add but on fx actually.
fun fx (SOME x) (SOME y) f = SOME (f x y)

Understanding typechecker behavior around `case->` [duplicate]

For example, how can I write a version of map that will work with polymorphic functions in Typed Racket? I use a simple id function defined as:
(: id : (All (A) A -> A))
(define (id x) x)
When I try to map it over a list i get an error:
> (map id '(1 2 3))
Type Checker: Polymorphic function `map' could not be applied to arguments:
Types: (-> a b ... b c) (Listof a) (Listof b) ... b -> (Listof c)
(-> a c) (Pairof a (Listof a)) -> (Pairof c (Listof c))
Arguments: (All (A) (-> A A)) (List One Positive-Byte Positive-Byte)
Expected result: AnyValues
in: (map id (quote (1 2 3)))
You have to manually instantiate the polymorphism in this case:
-> (map (inst identity Integer) '(1 2 3))
- : (Listof Integer) [more precisely: (Pairof Integer (Listof Integer))]
'(1 2 3)
The reason is explained in the Typed Racket Guide here:
Typed Racket’s local type inference algorithm is currently not able to
infer types for polymorphic functions that are used on higher-order
arguments that are themselves polymorphic.
(see docs for more explanation and examples)

How to implement "function" monads in racket using functional's data/monad module?

Since the data/monad module's do notation operates on structures, how can I define monad types that are functions, e.g. like parsers?
I'm used to OCaml, where my monad would have had roughly the following signature:
module type Parser = sig
type state = string * int
type 'a t = state -> (('a * state), string) Result.t
val return: 'a -> 'a t
val bind: 'a t -> ('a -> 'b t) -> 'b t
end
I'm sorry to post an example in OCaml, my racket abilities are not great for now.
Is this kind of monad compatible with data/monad, or should I look at another solution?
There’s nothing that prevents you from wrapping a function in a structure, then implementing the gen:monad interface on that structure. The megaparsack library is an example that uses that technique to implement a monadic parser combinator library. Specifically, take a look at the parser structure definition:
(struct parser (proc)
#:methods gen:functor
[(define/generic -map map)
(define (map f p)
(parser (compose (match-lambda [(consumed (ok v rest message)) (consumed (ok (-map f v) rest message))]
[(empty (ok v rest message)) (empty (ok (-map f v) rest message))]
[error error])
(parser-proc p))))]
#:methods gen:applicative
[(define (pure _ x)
(pure/p x))
(define (apply p ps)
(do [f <- p]
[xs <- (map/m values ps)]
(d:pure (r:apply f xs))))]
#:methods gen:monad
[(define (chain f p)
(parser
(λ (input)
(match (parse p input)
[(empty (ok (and foo (syntax-box x _)) rest message))
(match (parse (f x) rest)
[(empty reply) (empty (merge-message/reply message reply))]
[consumed consumed])]
[(consumed (ok (and foo (syntax-box x srcloc)) rest message))
(consumed (match (parse (f x) rest)
[(consumed (ok stx rest message))
(ok (merge-syntax-box/srcloc stx srcloc) rest message)]
[(empty (ok (syntax-box datum _) rest message))
(merge-message/reply message (ok (syntax-box datum srcloc) rest message))]
[(consumed error) error]
[(empty error) (merge-message/reply message error)]))]
[error error]))))])
This defines a structure type named parser containing a single field, proc, and implements the gen:functor, gen:applicative, and gen:monad interfaces on that structure type. The single field contains the parser procedure.

Why does `filter` work with higher-order occurrence typing?

On the homepage for Racket, they show this example:
#lang typed/racket
;; Using higher-order occurrence typing
(define-type SrN (U String Number))
(: tog ((Listof SrN) -> String))
(define (tog l)
(apply string-append (filter string? l)))
(tog (list 5 "hello " 1/2 "world" (sqrt -1)))
I know that with occurrence typing, an expression like (if (string? v) ...) will mark v as having type String in the true branch. This is because the type of string? has a filter on it:
> string?
- : (Any -> Boolean : String)
#<procedure:string?>
So, for "higher-order occurrence typing" to work with the filter function, I would expect the type of filter to say that a filter on the predicate's type gets propagated to the result type. But when I check the type of filter in the REPL, this doesn't show up:
> filter
- : (All (a b) (case-> ((a -> Any) (Listof a) -> (Listof b)) ((a -> Any) (Listof a) -> (Listof a))))
#<procedure:filter>
But this can't be the real type of filter, because there's no constraint on b! I expected something like
(All (a b) (a -> Any : b) (Listof a) -> (Listof b))
tldr: Why does filter appear have an unconstrained type variable in its return type?
EDIT: I am using Racket v6.0
In the Typed Racket Reference it is said:
In some cases, asymmetric type information is useful in filters. For example, the filter function’s first argument is specified with only a positive filter.
Example:
> filter
- : (All (a b)
(case->
(-> (-> a Any : #:+ b) (Listof a) (Listof b))
(-> (-> a Any) (Listof a) (Listof a))))
#<procedure:filter>
The use of #:+ indicates that when the function applied to a variable evaluates to a true value, the given type can be assumed for the variable. However, the type-checker gains no information in branches in which the result is #f.
In other words, if you have the following example:
> (filter string? '(symbol 1 2 3 "string"))
- : (Listof String)
'("string")
the system can says that an element of the list '(symbol 1 2 3 "string") is of type String only when string? returns true on it. Only in this case the type of the filter's predicate is propagated.

foldl definition possible wrong in SML/NJ 110.75

The signature of foldl in SML/NJ 110.75 is
foldl;
val it = fn : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
Also if I give:
foldl (op -) 2 [1];
I will take as answer ~1 instead of 1
Can you confirm my findings?
From the basis library: http://www.standardml.org/Basis/list.html#SIG:LIST.foldl:VAL
foldl f init [x1, x2, ..., xn]
returns
f(xn,...,f(x2, f(x1, init))...)
or init if the list is empty.
thus in foldl (op -) 2 [1] the result is the evaluation of xn - init or 1 - 2
What makes this particular example a bit harder to understand is that (op -) is a non-associative infix operator. So the f in the basis library definition gets moved between xn and init.
The signature is only for static type checking, and it is worth remembering that 'a and 'b may be of the same type.