Related
Can I use Kotlin FP (Lambda, function) to write a Y-combinator function?
Y = λf.(λx.f (x x)) (λx.f (x x))
In JS:
function Y(f) {
return (function (g) {
return g(g);
})(function (g) {
return f(function (x) {
return g(g)(x);
});
});
}
var fact = Y(function (rec) {
return function (n) {
return n == 0 ? 1 : n * rec(n - 1);
};
});
In Coffee:
coffee> Y = (f) -> ((x) -> (x x)) ((x) -> (f ((y) -> ((x x) y))))
[Function]
coffee> fact = Y (f) ->(n) -> if n==0 then 1 else n*f(n-1)
[Function]
coffee> fact(10)
3628800
How can I do this?
In Kotlin, you should introduce an additional interface G, Otherwise you will get the UNCHECKED_CAST warnings, since Kotlin is a statically typed programming language rather than a dynamic language, for example:
typealias X = (Int) -> Int
typealias F = Function1<X, X>
// v-------------v--- let G reference G recursively
interface G : Function1<G, X>
// v--- create a G from lazy blocking
fun G(block: (G) -> X) = object : G {
// v--- delegate call `block(g)` like as `g(g)`
override fun invoke(g: G) = block(g)
}
fun Y(f: F) = (fun(g: G) = g(g))(G { g -> f({ x -> g(g)(x) }) })
val fact = Y({ rec -> { n -> if (n == 0) 1 else n * rec(n - 1) } })
Another version cast a Function1<G, X> to a G, so it should suppress the UNCHECKED_CAST warnings, for example:
typealias X = (Int) -> Int
typealias F = Function1<X, X>
typealias G = Function1<Any, X>
#Suppress("UNCHECKED_CAST")
// v--- cast `g` to `G`.
fun Y(f: F) = (fun(g: Function1<G, X>) = g(g as G))({ g -> f { x -> g(g)(x) } })
val fact = Y({ rec -> { n -> if (n == 0) 1 else n * rec(n - 1) } })
I am trying to mock the awscala.dynamodbv2.DynamoDB.putConditionalMethod
How would one define an expects for a method which is curried and includes a repeated parameter:
putConditional(tableName: String, attributes: (String, Any)*)(cond: Seq[(String, aws.model.ExpectedAttributeValue)]): Unit
Here's what I've got working:
(mockClient.putConditional(_: String, _: (String, Any))(_: Seq[(String, ExpectedAttributeValue)]))
.expects("Data-Identity-Partitions",
*,
Seq(
"DatacenterId" -> exp.isNull,
"InstanceId" -> exp.isNull,
"TTL" -> exp.isNull
))
But this:
(mockClient.putConditional(_: String, _: (String, Any))(_: Seq[(String, ExpectedAttributeValue)]))
.expects("Data-Identity-Partitions",
Seq("DatacenterId" -> 1,
"InstanceId" -> 0,
"TTL" -> System.currentTimeMillis()),
Seq(
"DatacenterId" -> exp.isNull,
"InstanceId" -> exp.isNull,
"TTL" -> exp.isNull
))
results in the following compiler error:
[error] AwsPartitionActorSpec.scala:76: type mismatch;
[error] found : Seq[(String, Any)]
[error] required: org.scalamock.matchers.MockParameter[(String, Any)]
[error] Seq[(String, Any)]("DatacenterId" -> 1,
[error] ^
better late than never i suppose, here's my suggestion:
trait testtrait {
def foo(t: String, a: (String, Any) *): Int
}
"foo" should "work" in {
val m = mock[testtrait]
m.foo _ expects where {
case ("foo", Seq(("bar", 42L), ("baz", "mango"))) => true
case _ => false
} returns 5
m.foo("foo", ("bar", 42L), ("baz", "mango")) should be (5)
}
I have the next declarations of datatype and functions:
datatype direction = Back | Forward
datatype 'a bseq = bNil | bCons of 'a * (direction -> 'a bseq)
fun bHead (bCons (x, _)) = x
| bHead bNil = raise EmptySeq
fun bForward(bCons(_, xf)) = xf Forward
| bForward bNil = raise EmptySeq
fun bBack (bCons (_, xf)) = xf Back
| bBack bNil = raise EmptySeq
fun intbseq k =
let fun go Forward = intbseq (k+1)
| go Back = intbseq (k-1)
in bCons (k, go) end
The next function is written by me for interleaving two sequences like that:
if the first seq is ... ,1,2,3,4,5, ..... and the second is ...,5,6,7,8,9,...
The new sequance of their interleaving is:
... ,3,-1,4,0,5,1,6,2,7,3, ......
Code:
fun binterleaving_aux _ bNil yq = yq
| binterleaving_aux _ xq bNil = xq
| binterleaving_aux firstb (bCons(x,xf)) (bCons(y,yf)) =
bCons(x, fn dir =>
if dir = Forward
then binterleaving_aux true (bCons (y, yf)) (xf dir)
else if firstb
then binterleaving_aux false (yf dir) (xf dir)
else binterleaving_aux false (bCons (y,yf)) (xf dir)));
fun binterleaving bseq1 bseq2 = binterleaving_aux true bseq1 bseq2;
And for that exmaple:
binterleaving (intbseq 5) (intbseq 1);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);
It is working great for 2 infinite sequences.
The problem is when at least one of them is finite.
For exmaple if I do:
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 5);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);
If I go back I lose the 10 and 9, and the opposite if firstly I went back, when I move forward I lose them ether.
The result is by the order of the calls:
val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (4,fn) : int bseq
val it = bCons (3,fn) : int bseq
And the correct result should be:
val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (10,fn) : int bseq
What are the changes in the code I should do, so that will be the behavior of the function?
The problem is when at least one of them is finite.
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)
When your finite sequence reduces to bNil, how is it supposed to get back to its original values? The semantics of interleaving a finite sequence with an infinite one seem a little under-defined.
That is, when the finite one ends and the infinite one continues, where is the reference stored along the infinite sequence at which point the finite one starts again in reverse?
Take the example above and evaluate it a few steps (forgive my lazy notation):
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)
⇒ binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil))))
(bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ binterleaving_aux true (bCons(10, fn dir => bCons((9, fn dir => bNil))))
(bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ bCons (9, fn dir =>
if dir = Forward
then binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
((fn dir => bNil) dir)
else ...)
Evaluating this once by applying Forward to the outermost fn gives:
bCons (9, (fn dir => ...) Forward)
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
((fn dir => bNil) dir))
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...)) bNil)
⇒ bCons (9, bCons (0, fn dir => ...intbseq (+/- 1)...))
At this point, there is no trace of the finite sequence 9 in any function capable of going backward. Only in the initial return value of binterleaving.
The fix mainly lies in the base case of binterleaving which throws away the finite sequence. Rather, the result of interleaving an empty sequence with a non-empty sequence should be a non-empty sequence that, when reversed, returns whatever the empty sequence was before it got empty (which was possibly also empty, but possibly non-empty).
You can see your bidirectional sequence as a lazy zipper on lists. The book Learn You a Haskell has a chapter on tree zippers that might be worth a read. In this chapter's terminology, you might want a function that returns a "breadcrumb trail". List zippers are conceptually a bit simpler, but sprinkled with the laziness of 'a bseqs, syntactically not so.
If I have a string that looks like the name of a field in a record, can I use it to get the data somehow? Something like :
."name".toKey bill
bill.(asSymbol "name")
-
song =
{ title = "foot", artist = "barf", number = "13" }
fieldsILike : List String
fieldsILike =
[ "title", "artist" ]
val song key =
.key song
foo = List.map (val song) fieldsILike --> should be ["foot", "barf"]
No, but you could use a Dict
import Dict exposing (get ,fromList)
song = fromList [ ("title", "foot"), ("artist", "barf") ]
get "title" song -- Just "foot"
get "artist" song -- Just "barf"
get "test" song -- Nothing
Not the way you want it but you can have a function that pattern matches on a string to access a part of a record. You need to be explicit about what it should do in case you give it something invalid.
import Html exposing (..)
type alias Song = { artist : String, number : String, title : String }
song : Song
song =
{ title = "foot", artist = "barf", number = "13" }
fieldsILike : List String
fieldsILike =
[ "title", "artist" ]
k2acc : String -> (Song -> String)
k2acc key =
case key of
"title" -> .title
"artist" -> .artist
"number" -> .number
_ -> always ""
val : Song -> String -> String
val = flip k2acc
-- `flip` was removed in elm 0.19, so you'll need to
-- do something like the following going forward:
-- val song field = (k2acc field) song
foo = List.map (val song) fieldsILike
main = text <| toString foo
I solved this broblem by adding attribute's name and explicit type declaration in AttrValue type:
type alias TypedRecord =
List Attr
type alias Attr =
( String, AttrValue )
type AttrValue
= String String
| Int Int
| Record (List Attr)
So now i can retrieve attributes by "key" (even "key.key" for nested) from my TypedRecord type:
getAttrByKey : String -> TypedRecord -> Maybe Attr
getAttrByKey searchKey item =
-- imitation of searching for attributes likewise in JS Record
let
checkAttrKey =
\k attr ->
first attr == k
in
case String.split "." searchKey of
[ key ] ->
List.head <| List.filter (checkAttrKey key) item
key :: rest ->
case List.head <| List.filter (checkAttrKey key) item of
Just attr ->
case attr of
( _, Record subAttr ) ->
getAttrByKey (String.join "." rest) subAttr
( _, _ ) ->
Nothing
Nothing ->
Nothing
[] ->
Nothing
And conver it to String by checking Attr type and calling respected Elm String module function:
attrToString : Maybe Attr -> String
attrToString is_attr =
case is_attr of
Nothing ->
""
Just attr ->
case second attr of
String value ->
value
Int value ->
String.fromInt value
Record attrs ->
List.map (\a -> Just a) attrs
|> List.map (\a -> attrToString a)
|> String.join " "
These examples for String Int and Record Elm types, but it is also can be extended fo Float Bool and Array.
You can check src/lib/TypedRecord.elm file for another functions and even Json Decoder in my example app repository
Excuse me the lengthy example:
module type MONAD = sig
type ('r, 'a) t
val return : 'a -> ('r, 'a) t
val bind : ('r, 'a) t -> ('a -> ('r, 'b) t) -> ('r, 'b) t
end
module MonadOps (Monad : MONAD) = struct
include Monad
type ('r, 'a) monad = ('r, 'a) t
let run x = x
let return = Monad.return
let bind = Monad.bind
let (>>=) a b = bind a b
let rec foldM f a = function
| [] -> return a
| x::xs -> f a x >>= fun a' -> foldM f a' xs
let whenM p s = if p then s else return ()
let lift f m = perform x <-- m; return (f x)
let join m = perform x <-- m; x
let (>=>) f g = fun x -> f x >>= g
end
module Monad = (MonadOps : functor (M : MONAD) -> sig
type ('a, 'b) monad
val run : ('a, 'b) monad -> ('a, 'b) M.t
val return : 'a -> ('b, 'a) monad
val bind : ('a, 'b) monad -> ('b -> ('a, 'c) monad) -> ('a, 'c) monad
val ( >>= ) :
('a, 'b) monad -> ('b -> ('a, 'c) monad) -> ('a, 'c) monad
val foldM :
('a -> 'b -> ('c, 'a) monad) -> 'a -> 'b list -> ('c, 'a) monad
val whenM : bool -> ('a, unit) monad -> ('a, unit) monad
val lift : ('a -> 'b) -> ('c, 'a) monad -> ('c, 'b) monad
val join : ('a, ('a, 'b) monad) monad -> ('a, 'b) monad
val ( >=> ) :
('a -> ('b, 'c) monad) ->
('c -> ('b, 'd) monad) -> 'a -> ('b, 'd) monad
end)
module type MONAD_PLUS = sig
include MONAD
val mzero : ('r, 'a) t
val mplus : ('r, 'a) t -> ('r, 'a) t -> ('r, 'a) t
end
module MonadPlusOps (MonadPlus : MONAD_PLUS) = struct
include MonadOps (MonadPlus)
let mzero = MonadPlus.mzero
let mplus = MonadPlus.mplus
let fail = mzero
let (++) a b = mplus a b
let guard p = if p then return () else fail
end
Is there a way to have MonadPlus analogous to Monad without excessive signature code duplication? Along the lines of (wrong solution):
module MonadPlus = (MonadPlusOps : functor (M : MONAD_PLUS) -> sig
include module type of MonadPlusOps (M)
with type ('a, 'b) t := ('a, 'b) MonadPlusOps (M).monad
end)
or (does not type-check):
module MonadPlus = (MonadPlusOps : functor (M : MONAD_PLUS) -> sig
include module type of Monad(M)
val mzero : ('a, 'b) monad
(* ... *)
end)
Edit: updated -- better final solution
module type MONAD = sig
type ('s, 'a) t
val return : 'a -> ('s, 'a) t
val bind : ('s, 'a) t -> ('a -> ('s, 'b) t) -> ('s, 'b) t
end
module type MONAD_OPS = sig
type ('s, 'a) monad
include MONAD with type ('s, 'a) t := ('s, 'a) monad
val ( >>= ) :
('s, 'a) monad -> ('a -> ('s, 'b) monad) -> ('s, 'b) monad
val foldM :
('a -> 'b -> ('s, 'a) monad) -> 'a -> 'b list -> ('s, 'a) monad
val whenM : bool -> ('s, unit) monad -> ('s, unit) monad
val lift : ('a -> 'b) -> ('s, 'a) monad -> ('s, 'b) monad
val join : ('s, ('s, 'a) monad) monad -> ('s, 'a) monad
val ( >=> ) :
('a -> ('s, 'b) monad) ->
('b -> ('s, 'c) monad) -> 'a -> ('s, 'c) monad
end
module MonadOps (M : MONAD) = struct
open M
type ('s, 'a) monad = ('s, 'a) t
let run x = x
let (>>=) a b = bind a b
let rec foldM f a = function
| [] -> return a
| x::xs -> f a x >>= fun a' -> foldM f a' xs
let whenM p s = if p then s else return ()
let lift f m = perform x <-- m; return (f x)
let join m = perform x <-- m; x
let (>=>) f g = fun x -> f x >>= g
end
module Monad (M : MONAD) =
sig
include MONAD_OPS
val run : ('s, 'a) monad -> ('s, 'a) M.t
end = struct
include M
include MonadOps(M)
end
module type MONAD_PLUS = sig
include MONAD
val mzero : ('s, 'a) t
val mplus : ('s, 'a) t -> ('s, 'a) t -> ('s, 'a) t
end
module type MONAD_PLUS_OPS = sig
include MONAD_OPS
val mzero : ('s, 'a) monad
val mplus : ('s, 'a) monad -> ('s, 'a) monad -> ('s, 'a) monad
val fail : ('s, 'a) monad
val (++) : ('s, 'a) monad -> ('s, 'a) monad -> ('s, 'a) monad
val guard : bool -> ('s, unit) monad
end
module MonadPlus (M : MONAD_PLUS) :
sig
include MONAD_PLUS_OPS
val run : ('s, 'a) monad -> ('s, 'a) M.t
end = struct
include M
include MonadOps(M)
let fail = mzero
let (++) a b = mplus a b
let guard p = if p then return () else fail
end
I'm not entirely sure what you are trying to achieve, but I would perhaps try to factor it as follows:
module type MONAD =
sig
type ('r, 'a) t
val return : 'a -> ('r, 'a) t
val bind : ('r, 'a) t -> ('a -> ('r, 'b) t) -> ('r, 'b) t
end
module type MONAD_OPS =
sig
type ('a, 'b) monad
val run : ('a, 'b) monad -> ('a, 'b) monad
val (>>=) : ('a, 'b) monad -> ('b -> ('a, 'c) monad) -> ('a, 'c) monad
(* ... *)
end
module MonadOps (Monad : MONAD) :
sig
include MONAD with type ('a ,'b) t := ('a, 'b) Monad.t
include MONAD_OPS with type ('a ,'b) monad = ('a, 'b) Monad.t
end =
struct
include Monad
type ('r, 'a) monad = ('r, 'a) t
let run x = x
let (>>=) = bind
let rec foldM f a = function
| [] -> return a
| x::xs -> f a x >>= fun a' -> foldM f a' xs
(* ... *)
end
module type MONAD_PLUS = sig
include MONAD
val mzero : ('r, 'a) t
val mplus : ('r, 'a) t -> ('r, 'a) t -> ('r, 'a) t
end
module type MONAD_PLUS_OPS =
sig
include MONAD_OPS
val fail : ('r, 'a) monad
val (++) : ('r, 'a) monad -> ('r, 'a) monad -> ('r, 'a) monad
(* ... *)
end
module MonadPlusOps (MonadPlus : MONAD_PLUS) :
sig
include MONAD_PLUS with type ('a ,'b) t := ('a, 'b) Monad.t
include MONAD_PLUS_OPS with type ('a ,'b) monad = ('a, 'b) Monad.t
end =
struct
include MonadPlus
include MonadOps (MonadPlus)
let fail = mzero
let (++) = mplus
(* ... *)
end
As a complement to Andreas' answer, I wished to show that you can use functors to produce signatures. I haven't exactly followed the discussion on which exact level of type abstraction you want, so this code is to be compared with Andreas' version.
module MonadSig = struct
module type S = sig
type ('r, 'a) t
val return : 'a -> ('r, 'a) t
val bind : ('r, 'a) t -> ('a -> ('r, 'b) t) -> ('r, 'b) t
end
end
module MonadOpsSig (M : MonadSig.S) = struct
module type S = sig
type ('a, 'b) monad = ('a, 'b) M.t
val run : ('a, 'b) monad -> ('a, 'b) monad
val (>>=) : ('a, 'b) monad -> ('b -> ('a, 'c) monad) -> ('a, 'c) monad
(* ... *)
end
end
module MonadOps (M : MonadSig.S) : MonadOpsSig(M).S = struct
open M
type ('r, 'a) monad = ('r, 'a) t
let run x = x
let (>>=) = bind
let rec foldM f a = function
| [] -> return a
| x::xs -> f a x >>= fun a' -> foldM f a' xs
(* ... *)
end
module MonadPlusSig = struct
module type S = sig
include MonadSig.S
val mzero : ('r, 'a) t
val mplus : ('r, 'a) t -> ('r, 'a) t -> ('r, 'a) t
end
end
module MonadPlusOpsSig (Monad : MonadPlusSig.S) = struct
module type S = sig
include MonadOpsSig(Monad).S
val fail : ('r, 'a) monad
val (++) : ('r, 'a) monad -> ('r, 'a) monad -> ('r, 'a) monad
(* ... *)
end
end
module MonadPlusOps (M : MonadPlusSig.S) : MonadPlusOpsSig(M).S = struct
include MonadOps(M)
open M
let fail = mzero
let (++) = mplus
(* ... *)
end
The idea is that to provide a signature parametrized on something, you can either embed this signature into a parametrized functor (I'd call this the "functor style"), or define the parameters as abstract (but they're really inputs rather than outputs) and, at use site, equate them with the actual parameters (I'd call this the "mixin style"). I'm not saying the code above is better than Andreas', in fact I'd probably rather use his version, but its interesting to compare them.