Rationale for order of arguments to `get` function - elm

Why are the arguments ordered the way they are in Array.get and Dict.get? The order in most map/filter functions makes sense: the function comes before the collection (or monad, more generally).
MyCollection.map : (a -> b) -> MyCollection a -> MyCollection b
This makes it easier to compose higher functions out of smaller ones before passing in a collection.
Why, however, does the index/key come before the collection in get functions?
Dict.get : comparable -> Dict comparable v -> Maybe v
It seems to make it harder to compose higher functions. If the arguments were reversed, one could write:
ids : List Int
myObjects : Dict Int a
selectObjects = List.map (Dict.get myObjects) ids
But instead, the best way I can come up with to write this is:
ids : List Int
myObjects : Dict Int a
selectObjects = List.map (\id -> (Dict.get id myObjects)) ids
Am I missing something? What is the reason for the argument order in Array.get, Dict.get, and similar?

List.map (Dict.get myObjects) ids isn't function composition.
Composition is when you have
f : X -> Y and
g : Y -> Z then you compose them
h = f >> g so that
h : X -> Z
Now, when composing functions as above, we need them to require ONLY one more parameter.
So when defining an API, the question is:
"When someone partially evaluates this function so that it can be composed, what is the last parameter they'll likely want to pass it?"
In other words, are we more likely to see code like:
getStuff >> mungeIntoDict >> (Dict.get id)
or
getStuff >> getImportantId >> (Dict.get myDict)
?
The answer to that is "it depends". The API designers took their best guess and we have flip for when it doesn't suit us.

Related

Partial application of Printf.ksprintf

I'm trying to write a version of Printf.printf that always appends a newline character after writing its formatted output. My first attempt was
# let say fmt = Printf.ksprintf print_endline fmt;;
val say : ('a, unit, string, unit) format4 -> 'a = <fun>
The type signature looks right and say works as expected. I noticed that fmt is listed twice, and thought that partial application could eliminate it. So I tried this instead:
# let say = Printf.ksprintf print_endline;;
val say : ('_weak1, unit, string, unit) format4 -> '_weak1 = <fun>
The function definition looks cleaner, but the type signature looks wrong and say no longer works as expected. For example, say doesn't type check if the format string needs a variable number of arguments: I get an error that say "is applied to too many arguments".
I can use the let say fmt = … implementation, but why doesn't partial application work?
OCaml's type-checker loses polymorphism during partial application. That is, when you partially apply a function, the resulting function is no longer polymorphic. That's why you see '_weak1 in the second type signature.
When you include the fmt argument, you help the type-checker recognize that polymorphism is still present.
This process is called "eta conversion." Removing your fmt argument is "eta reduction" and adding it back in is called "eta expansion." You may encounter that terminology when working with other functional programming languages.
This is the value restriction at work: https://ocaml.org/manual/polymorphism.html#s:weak-polymorphism . In brief, only syntactic values can be safely generalized in let-binding in presence of mutable variables in the language.
In particular,
let f = fun x -> g y x
is a syntactic value that can be generalized, whereas
let f = g y
is a computation that cannot (always) be generalized.
A example works quite well to illustrate the issue, consider:
let fake_pair x =
let store = ref None in
fun y ->
match !store with
| None ->
store := Some y;
x, y
| Some s ->
x, s
then the type of fake_pair is 'a -> 'b -> 'a * 'b.
However, once partially applied
let p = fake_pair 0
we have initialized the store mutable value, and it is important that all subsequent call to p share the same type (because they must match the stored value). Thus the type of p is '_weak1 -> int * '_weak1 where '_weak1 is a weak type variable, aka a temporary placeholder for a concrete type.

Generic pattern matching in Elm

I'm trying to build a generic mapping function that will extract a possible inner type from a union type, apply a transform to the inner value and map it back to the outer type.
The trouble is, I need a way to distinguish if a specific value of the outer type has an inner type at all.
It would work for me if the code below actually compiled, but Elm doesn't allow constants in pattern matches. (constructor on line 4 fails to compile)
Is there any other way to accomplish this?
map : (inner -> outer) -> (inner -> inner) -> outer -> outer
map constructor func current =
case current of
constructor child ->
constructor (func child)
_ ->
current
No, unfortunately Elm doesn't have a way to express this kind of thing generically, you need to write a specific version for each custom type.
You can take a look to the elm-accessors library. With it you will need to define a Relation for every of yours type constructor (it is pretty straightforward). But then you'll be free to use a good old List.map to map over any constructor!
Here is a usage example:
type FooBar a b
= Foo a
| Bar b
items =
List.map
(over (foo << try) ((+) 1) -- affects only "Foo"s
<<
over (bar << try) (\b -> b ++ "!")) -- affects only "Bar"s
[Foo 1, Bar "a", Foo 10]
-- = [Foo 2,Bar "a!",Foo 11]
Here is a live version (Ellie).

List of types from a function type

I would like to make a function that given a function type (e.g. String -> Nat -> Bool), would return a list of types corresponding to that function type (e.g. [String, Nat, Bool]). Presumably the signature of such a function would be Type -> List Type, but I am struggling to determine how it would be implemented.
I don't believe it could be done in general, because you cannot patter-match on functions. Neither can you check for the type of a function. That is not what dependent types are about. Just like in Haskell or OCaml the only thing you can actually do with a function is apply it to some argument. However, I devised some trick which might do:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = [a, b]
Now the problem is that a -> b is the only signature that would match any arbitrary function. But, of course it does not behave the way you'd like for functions with arity higher than one:
> myFun (+)
[Integer, Integer -> Integer] : List Type
So some sort of recursive call to itself would be necessary to extract more argument types:
myFun : {a, b : Type} -> (a -> b) -> List Type
myFun {a} {b} _ = a :: myFun b
The problem here is that b is an arbitrary type, not necessarily a function type and there is no way I can figure out to dynamically check whether it is a function or not, so I suppose this is as much as you can do with Idris.
However, dynamic checking for types (at least in my opinion) is not a feature to be desired in a statically typed language. After all the whole point of static typing is to specify in advance what kind of arguments a function can handle and prevent calling functions with invalid arguments at compile time. So basically you probably don't really need it at all. If you specified what you grander goal was, someone would likely have shown you the right way of doing it.

Is there a nice way to use `->` directly as a function in Idris?

One can return a type in a function in Idris, for example
t : Type -> Type -> Type
t a b = a -> b
But the situation came up (when experimenting with writing some parsers) that I wanted to use -> to fold a list of types, ie
typeFold : List Type -> Type
typeFold = foldr1 (->)
So that typeFold [String, Int] would give String -> Int : Type. This doesn't compile though:
error: no implicit arguments allowed
here, expected: ")",
dependent type signature,
expression, name
typeFold = foldr1 (->)
^
But this works fine:
t : Type -> Type -> Type
t a b = a -> b
typeFold : List Type -> Type
typeFold = foldr1 t
Is there a better way to work with ->, and if not is it worth raising as a feature request?
The problem with using -> in this way is that it's not a type constructor but a binder, where the name bound for the domain is in scope in the range, so -> itself doesn't have a type directly. Your definition of t for example wouldn't capture a dependent type like (x : Nat) -> P x.
While it is a bit fiddly, what you're doing is the right way to do this. I'm not convinced we should make special syntax for (->) as a type constructor - partly because it really isn't one, and partly because it feels like it would lead to more confusion when it doesn't work with dependent types.
The Data.Morphisms module provides something like this, except you have to do all the wrapping/unwrapping around the Morphism "newtype".

Using function like OOP method in Haskell

I'm studying Haskell these days, and got a idea using function like OOP method.
First, define a operator as below:
(//) :: a -> (a -> b) -> b
x // f = f x
As you can see, this operator reverses the order of function f and argument x then applies it. For example, equals can be defined as:
equals :: Eq a => a -> a -> Bool
equals = \x -> \y -> x == y
comparison = (1 + 2) // equals 3 -- True
Now here is my question. Is it good approach using Haskell function like OOP method? That means inversion of function and (first) argument is good or not.
UPDATE
Here is the case of backtick(`) is not available.
data Person = Person { name :: String }
myself = Person "leafriend"
then
> name myself
"leafriend"
> myself // name
"lefirend"
> myself `name`
ERROR - Syntax error in expression (unexpected end of input)
What you have written is merely a matter of style. (It seems rather cruel to C/Java programmers to use // as an operator, though.) I would discourage using this for a few reasons, mainly because:
It's not idiomatic Haskell, and will confuse any Haskellers trying to read your code
You shouldn't think of Haskell as you would think of an OOP language
If you're trying to make Haskell look more like your favorite OOP language, you're doing it wrong. Haskell is meant to look like math: kind of lisp-y, with prefix function application, but also with infix functions and operators available.