对于学校的编码工作,我必须做平板图的工作,但我完全不知道它做了什么,我已经在网上阅读了几页并阅读了我的教科书,但我仍然没有真正理解它的作用。我知道地图有什么作用,但由于某种原因,我很难将头部包裹在flatmap中。有人可以帮忙吗?谢谢。
只是添加更多信息 - 当我在线查看示例时,我会看到flatmap如何返回与地图不同的内容。但是当flatmap被调用时,它实际上在做什么呢? flatmap如何实际工作?它在返回结果之前做了什么?
答案 0 :(得分:6)
这是一个类比。
想象一下,你有一个装满纸箱的购物券的大包。如果你有一个“使用优惠券购买一盒鸡蛋”的功能,而你打电话给bigBagOfVouchers.map(buyCartonOfEggs)
,你就会得到一袋纸箱。
但是,如果你打电话给bigBagOfVouchers.flatMap(buyCartonOfEggs)
,你就会有一袋鸡蛋 - 没有任何纸箱。
flatMap
将结果展平一级。可能Bag[Carton[Egg]]
现在是Bag[Egg]
。
答案 1 :(得分:5)
Functors定义具有类型
的地图trait Functor[F[_]] {
def map[A, B](f: A => B)(v: F[A]): F[B]
}
Monads是函数,它支持两个额外的操作:
trait Monad[M[_]] extends Functor[M] {
def pure[A](v: A): M[A]
def join[A](m: M[M[A]]): M[A]
}
加入展平嵌套值,例如如果m
为List
,则join
的类型为
def joinList[A](l: List[List[A]]): List[A]
如果你有一个monad m
而你map
,那么如果b
是同一个monadic类型会怎样?例如:
def replicate[A](i: Int, value: A): List[A] = ???
val f = new Functor[List] {
def map[A, B](f: A => B)(v: List[A]) = v.map(f)
}
然后
f.map(x => replicate(x, x))(List(1,2,3)) == List(List(1), List(2,2), List(3,3,3))
此类型为List[List[Int]]
,而输入为List[Int]
。对于希望每个步骤返回相同输入类型的操作链而言,这是相当常见的。由于List
也可以制作为monad,因此您可以使用join
轻松创建此类列表:
listMonad.join(List(List(1), List(2,2), List(3,3,3))) == List(1,2,2,3,3,3)
现在您可能想编写一个函数将这两个操作合并为一个:
trait Monad[M] {
def flatMap[A, B](f: A => M[B])(m: M[A]): M[B] = join(map(f)(m))
}
然后你就可以做到:
listMonad.flatMap(List(1,2,3), x => replicate(x, x)) == List(1,2,2,3,3,3)
flatMap
完全取决于monad类型构造函数M
(本例中为List
),因为它取决于map
和join
。
答案 2 :(得分:0)
在反应式编程中,您经常遇到需要使用 flatMap 将 Future [Future [List]] 转换为 Future [List]的情况] 。例如,您有两个功能: get 来自数据库的用户和进程检索到的用户;并返回 Future [List [User]] 。如果您将地图应用于获取和进程,结果将是 Future [Future [List [User]]] 这没有任何意义。相反,您应该使用flatMap:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.Net;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string Address= "*PUT IP ADDRESS HERE WHERE UDP SERVER IS*";
int UDPPort = *PUT UDP SERVER PORT HERE*;
UdpRedirect _UdpRedirect = new UdpRedirect() { _address = Address, _Port = UDPPort};
Thread _Thread = new Thread(_UdpRedirect.Connect);
_Thread.Name = "UDP";
_Thread.Start();
int TCPPort = *PUT TCP PORT HERE FOR TCP PROXY*;
TcpRedirect _TcpRedirect = new TcpRedirect(Address, TCPPort);
}
}
class UdpRedirect
{
public string _address;
public int _Port;
public UdpRedirect()
{
}
public void Connect()
{
UdpClient _UdpClient = new UdpClient(_Port);
int? LocalPort = null;
while (true)
{
IPEndPoint _IPEndPoint = null;
byte[] _bytes = _UdpClient.Receive(ref _IPEndPoint);
if (LocalPort == null) LocalPort = _IPEndPoint.Port;
bool Local = IPAddress.IsLoopback(_IPEndPoint.Address);
string AddressToSend = null;
int PortToSend = 0;
if (Local)
{
AddressToSend = _address;
PortToSend = _Port;
}
else
{
AddressToSend = "127.0.0.1";
PortToSend = LocalPort.Value;
}
_UdpClient.Send(_bytes, _bytes.Length, AddressToSend, PortToSend);
}
}
}
class TcpRedirect
{
public TcpRedirect(string _address, int _Port)
{
TcpListener _TcpListener = new TcpListener(IPAddress.Any, _Port);
_TcpListener.Start();
int i = 0;
while (true)
{
i++;
TcpClient _LocalSocket = _TcpListener.AcceptTcpClient();
NetworkStream _NetworkStreamLocal = _LocalSocket.GetStream();
TcpClient _RemoteSocket = new TcpClient(_address, _Port);
NetworkStream _NetworkStreamRemote = _RemoteSocket.GetStream();
Console.WriteLine("\n<<<<<<<<<connected>>>>>>>>>>>>>");
Client _RemoteClient = new Client("remote" + i)
{
_SendingNetworkStream = _NetworkStreamLocal,
_ListenNetworkStream = _NetworkStreamRemote,
_ListenSocket = _RemoteSocket
};
Client _LocalClient = new Client("local" + i)
{
_SendingNetworkStream = _NetworkStreamRemote,
_ListenNetworkStream = _NetworkStreamLocal,
_ListenSocket = _LocalSocket
};
}
}
public class Client
{
public TcpClient _ListenSocket;
public NetworkStream _SendingNetworkStream;
public NetworkStream _ListenNetworkStream;
Thread _Thread;
public Client(string Name)
{
_Thread = new Thread(new ThreadStart(ThreadStartHander));
_Thread.Name = Name;
_Thread.Start();
}
public void ThreadStartHander()
{
Byte[] data = new byte[99999];
while (true)
{
if (_ListenSocket.Available > 0)
{
int _bytesReaded = _ListenNetworkStream.Read(data, 0, _ListenSocket.Available);
_SendingNetworkStream.Write(data, 0, _bytesReaded);
Console.WriteLine("(((((((" + _bytesReaded + "))))))))))" + _Thread.Name + "\n" + ASCIIEncoding.ASCII.GetString(data, 0, _bytesReaded).Replace((char)7, '?'));
}
Thread.Sleep(10);
}
}
}
}
}